Introduction
Sparki features several communications capabilities. Among them are two easy to use serial ports. One of them is a serial connection that works through the USB cable that you can use to program the Sparki. The other serial port is a Bluetooth wireless module (also available for advanced uses in the Expansion Port). A quick note about failing to upload code- Sometimes Sparki gets hung up and you can’t upload code to it because there is serial communication happening. If this happens try turning Sparki off, unplugging your USB from both Sparki and the computer, waiting for at least thirty seconds and then plugging everything back in before trying to upload code again. If Sparki still won’t accept code try doing everything I just outlined AND closing the SparkiDuino application. If you’re having trouble try this.What You’ll Need
- A Sparki.
- The Bluetooth module included with Sparki.
Setting up the USB serial connection
Making your Sparki communicate with your computer using the USB cable is easy. You just need to have your SparkiDuino software installed, and the Sparki plugged into your computer through the USB port: And of course, please don’t forget to select the corresponding serial port in the Tools->Serial Port menu. You can take a look at this page if you need more information about that. Finally, to effectively communicate with Sparki’s port from the computer, we need to use SparkiDuino’s terminal (also called Serial Monitor), which can be opened both with the Tools->Serial Monitor menu or with the following button: Note: When programming the Sparki, please be patient and do not open the SparkiDuino’s terminal until the programs that you are going to use here have been completely uploaded to your Sparki. You should see a message similar to the following, once the SparkiDuino environment has finished the upload process:Hello World
Let’s start by sending a small piece of text from your Sparki to your SparkiDuino‘s terminal (which will be running on your computer). The text to be sent will be the phrase “Hello World”. To do that, we will use the Serial.println command. Here is the code:
1 2 3 4 5 6 7 8 9 10 11 |
#include <Sparki.h> // include the sparki library void setup() { } void loop() { Serial.println("Hello World"); delay(1000); } |
Serial.Println and Serial.Print
At this point you may have noted that the Serial.println adds a “new line” after sending the text to the terminal. If you want to send text without it, you can always use the similar Serial.print command. For example, if you modify a bit our prior program, you will clearly see the difference:
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <Sparki.h> // include the sparki library void setup() { } void loop() { //Serial.println("Hello World"); Serial.print("Hello World"); delay(1000); } |
Echo
Now that we have a basic understanding of the serial communications on our robot, let’s do something a bit more complex: an echo program. The idea here is program Sparki so we can send characters to it, and then see it send them back to us in the serial terminal. To start with we will use the USB cable, so make sure that you leave your Sparki plugged in after uploading code. To see Sparki “echo” our typing, we will need to use the Serial.read instruction. Each step of the simple code below is outlined in the following steps:- Serial.read will get the last received character from the serial port and store it in a variable. In this code the variable is called “inByte.” We call it that because it is “incoming” information and it’s size is exactly one byte. If you’re interested in learning more about why it’s important to know about the size of your variable, click here.
- After that, the stored character will be sent again back to the computer using the Serial.print command. The (char) portion of the code makes sure that Sparki is converting the communication variable information into a character type variable so that we can read it as text.
- The program will also only read the serial port when it knows that there is new data available. To do this, we will use an if-statement where the program will ask if there is new data using the Serial.available command. Only if there is information waiting for Sparki to read from the serial port with the USB cable will the two lines of code above execute. Here is the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <Sparki.h> // include the sparki library void setup() { } void loop() { if (Serial.available()) { int inByte = Serial.read(); Serial.print((char)inByte); } } |
Then you can press the both the ENTER key in your keyboard, or the Send button on the screen to send the text that you have entered, and Sparki will answer with the same text:
It may seem like the Terminal is just displaying the information you typed into it below, but I promise you, that’s not the case. The information first gets sent to Sparki through the USB cable. The communication you see in the Terminal is also displaying like a Serial.println command, even though we are using a Serial.print command. What’s going on there? This is because when you press the Return key or the Send button you’re sending a carriage return to Sparki along with your message. Then Sparki reads in the information before sending it back to the computer. To test this try adding an “else” statement to the code above so that Sparki tells you when there is no incoming information on the Serial port:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <Sparki.h> // include the sparki library void setup() { } void loop() { if (Serial.available()) { int inByte = Serial.read(); Serial.print((char)inByte); } else { Serial.println("There's no communication, I'm bored!"); delay(100); } } |
Printing Other Data Types
A very useful feature of both Serial.print and Serial.println instructions is that they can work with different data types. So we can print not just text (or strings) and characters, but also integer and floating point numbers, as can be seen in this short program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <Sparki.h> // include the sparki library int counter = 0; // integer variable. float x = 0.0; // floating point variable. void setup() { } void loop() { Serial.print("Counter = "); Serial.println(counter); // prints an integer value Serial.print("x = "); Serial.println(x); // prints a floating point value Serial.println(); // prints an empty line counter++; // increment the counter variable x = x + 0.2; // increment the x variable in 0.2 steps delay(500); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <Sparki.h> // include the sparki library void setup() { } void loop() { Serial.print("Distance = "); Serial.print(sparki.ping()); Serial.println(" cm"); delay(300); } |
Setting Up the Bluetooth Serial Connection
The Bluetooth module is included with Sparki, but you have to plug it into the robot’s Expansion Port in order to use it. Also, it’s necessary to configure the connection from your computer before starting to use this useful part. Please make sure that you have followed the steps in this lesson before continue with the next examples here. Once this is done, using the Bluetooth module is as easy as using the USB serial port previously seen here. Except you get to unplug your Sparki from the computer! The only change that you need to make in your programs is to replace the Serial keyword by Serial1. Let’s see some examples…Bluetooth Testing: Hello World
The first test that we should do to ensure that our Bluetooth module is working fine is to run the Hello World program, but where we used Serial we want to change that to Serial1. We’ll also need to add the Serial1.begin(9600) command to the setup function. This command tells Sparki that the communication we’ll be sending over the Bluetooth Module will be at a speed of 9,600 bits per second or a baud rate of 9600. It’s important to be aware of this number because it needs to match in the code running on Sparki and in the program on your computer or device you use to receive the communication from Sparki. If Sparki is “speaking” at a faster or slower speed than your receiving device can “listen” (if the baud rates don’t match up) then the communication will be show up as gibberish.
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <Sparki.h> // include the sparki library void setup() { Serial1.begin(9600); } void loop() { Serial1.println("Hello World"); delay(1000); } |
What your Serial Monitor should look like
Making a Serial Bridge Between the USB and the Bluetooth ports
Let’s test bidirectional communications, but instead of just running the echo program for Serial1 (which you can test of course if you want!), we will make something a bit more interesting: a bridge between the USB and the Bluetooth ports. With it, we will be able to send text from one port and see it on the other one. To do this though, we will need two terminals. We can run two instances of PuTTY, or open the SparkiDuino’s terminal for the USB port, and the PuTTY terminal for the Bluetooth. If you’re using a Mac and you really don’t want to work with a Terminal program like PuTTY (CoolTermMac is a nice, fairly simple Terminal program that I use) you can download and install Arduino, which is almost exactly like SparkiDuino. Then you can use the Serial Monitors in Arduino and SparkiDuino to talk over the USB port and the Bluetooth Module. Before we look at any terminals, Mac or PC, here is the code, which is similar to the echo program, but a bit more complex since it deals with two ports instead of one:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <sparki.h>; // include the sparki library void setup() { Serial1.begin(9600); } void loop() { if (Serial1.available()) { int inByte = Serial1.read(); Serial.print((char)inByte); } if (Serial.available()) { int inByte = Serial.read(); Serial1.print((char)inByte); } }</sparki.h> |
Advanced Bluetooth Communication Lessons
Ok, now that you feel comfortable with basic serial communication and have used the Bluetooth Module a little let’s do something more interesting like controlling how your Sparki rolls around using Bluetooth serial commands. Let’s use pseudo-code to think about the various things we need Sparki’s code to do before we start writing it:- Read in serial communication from the Bluetooth Module
- Store the value of that communication in a String variable
- Compare the communication in the String variable to a list of commands that will make Sparki perform actions
- Make Sparki perform the action that is associated with a command
- Make Sparki stop and wait for more serial communication after performing the action
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <Sparki.h> // include the sparki library void setup() { Serial1.begin(9600); } void loop() { if (Serial1.available()) { int inByte = Serial1.read(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <Sparki.h> // include the sparki library String inputString; //make an empty String called inputString void setup() { Serial1.begin(9600); } void loop() { if (Serial1.available()) { int inByte = Serial1.read(); inputString += (char)inByte; //add the character from bluetooth to the string } Serial1.println(inputString); //this code is for debugging and checking comm. } |
So when there was just one word, “Right” everything was pretty normal, correct? But then we added a second word to the communication and it turned up on a second line. That’s because the carriage return (our pressing of the Return button) also gets stored in the inputString! So if you keep adding more and more communications to this you’ll get a longer and longer set of words being stored inside inputString. That’s no good for what we want our code to do, is it? No, it’s not. So we need to add a little bit of code that resets inputString to an empty String if there is a new line of communication coming over the Bluetooth Module.
We’ll reset the String by using a “flag.” Before the inByte character is stored in the inputString we’ll check to see if it’s a carriage return, which looks like a slash and an N- ‘n’. If it a carriage return is we won’t bother to store the carriage return in the String, but we will set the flag so that next time there is some communication the inputString resets to an empty String. If the character isn’t a carriage return we’ll concatenate the character into inputString and set the flag to false. We’ll also need to reset the flag after we clear out inputString. Here’s the code to do all that:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include <Sparki.h> // include the sparki library String inputString; //make an empty String called inputString boolean returnFlag; //flag to check for carriage return void setup() { Serial1.begin(9600); } void loop() { if (Serial1.available()) { if (returnFlag) { inputString = ""; returnFlag = false; } int inByte = Serial1.read(); if ((char)inByte == 'n') { returnFlag = true; } else { inputString += (char)inByte; //add the character from bluetooth to string } } Serial1.println(inputString); //this code is for debugging and checking comm. } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
void loop() { if (Serial1.available()) { if (returnFlag) { inputString = ""; returnFlag = false; } int inByte = Serial1.read(); if ((char)inByte == 'n') { returnFlag = true; } else { inputString += (char)inByte; //add the character from bluetooth to string } } Serial1.println(inputString); //this code is for debugging and checking comm. //here's the code I'm adding this time around if (inputString == "Forward") { sparki.moveForward(); } else if (inputString == "Left") { sparki.moveLeft(); } else if (inputString == "Right") { sparki.moveRight(); } else if (inputString == "Stop") { sparki.moveStop(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
void loop() { if (Serial1.available()) { if (returnFlag) { inputString = ""; returnFlag = false; } int inByte = Serial1.read(); if ((char)inByte == 'n') { returnFlag = true; } else { inputString += (char)inByte; //add the character from bluetooth to string } } Serial1.println(inputString); //this code is for debugging and checking comm. //here's the code I'm adding this time around if (inputString == "Forward" || inputString == "forward" || inputString == "Go") { sparki.moveForward(); } else if (inputString == "Left" || inputString == "left") { sparki.moveLeft(); } else if (inputString == "Right" || inputString == "right") { sparki.moveRight(); } else if (inputString == "Stop" || inputString == "stop") { sparki.moveStop(); } } |
Sending Multiple Commands in One Line of Communication
There’s one last way to make our communication with Sparki very robust that we’ll cover in this lesson. What if a user wants to send Sparki a set of words that will make Sparki perform actions, all with one line of communication? We’ll cover the code you need to use to help Sparki understand multiple words in a single line of communication. Ok, pseudo-code time. Here’s a brief list of what we need to accomplish, there might be bits we miss but we’ll add that in as we go and problems arise. You should be used to this by now….- Send a communication from Sparki to the Terminal explaining how to communicate with Sparki and wait for the Terminal user to respond with “OK”
- Create an array of Strings to hold incoming words and parameters
- Create a counter variable to keep track of where we are in the word array
- Create a boolean variable to keep track of whether Sparki is ready to receive a communication from the Terminal
- Store information from Bluetooth communication in the array of Strings
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
#include <Sparki.h> // include the sparki library String inputString; //make an empty String called inputString boolean returnFlag; //flag to check for carriage return boolean oKSent; //flag to check for OK communication void setup() { Serial1.begin(9600); } void loop() { while (oKSent == false) { //start code for reading in communication if (Serial1.available()) { if (returnFlag) { inputString = ""; returnFlag = false; } int inByte = Serial1.read(); if ((char)inByte == 'n') { returnFlag = true; } else { inputString += (char)inByte; //add the character from bluetooth to string } } //end code for reading in communication //start code to check for OK communication if ((inputString == "OK" || inputString == "ok" || inputString == "Ok") && returnFlag == true) { Serial1.println("Have fun sending Sparki movement commands!"); oKSent = true; //exit the OK while loop } //end code to check for OK communication else //send instructions once a second { Serial1.println("Sparki expects to receive communication that are"); Serial1.println("movement commands (Forward, Right, Left, Stop)"); Serial1.println("separated by spaces."); Serial1.println("Do not send Sparki more than ten commands at a time."); Serial1.println("The line below is an example of valid communication."); Serial1.println("Forward Right Forward Left Forward"); Serial1.println("Type OK and press Send or Return to continue."); Serial1.println();//empty line to separate messages delay(2000); } } |
1 |
if (Serial1.available()) |
1 |
while (Serial1.available()) |
1 2 |
String inputString; String commArray [10]; |
1 2 3 4 |
String inputString; String commArray [10]; int arrayCounter = 0; boolean commReady; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
#include <Sparki.h> // include the sparki library String inputString; //make an empty String called inputString boolean returnFlag; //flag to check for carriage return boolean oKSent; //flag to check for OK communication String commArray [10]; //array to store communication int arrayCounter = 0; //integer to count through commArray void setup() { Serial1.begin(9600); } void loop() { instructions(); readComm(); } void readComm() { while (Serial1.available()) { int inByte = Serial1.read(); if ((char)inByte == 'n') { returnFlag = true; arrayCounter = 0; } else { //here is where the code differs a lot from the previous code if(inByte == 32) //if it's a blank space { arrayCounter ++; //increment array counter to store in new array space } else { //add the character to the arrayCounter space in commArray commArray[arrayCounter] += (char)inByte; } } } //debugging/checking to make sure it works for(int i = 0; i <=9; i++) { Serial1.println(commArray[i]); } } void instructions() { //Start code for instructions while (oKSent == false) { //start code for reading in communication while (Serial1.available()) { if (returnFlag) { inputString = ""; returnFlag = false; } int inByte = Serial1.read(); if ((char)inByte == 'n') { returnFlag = true; } else { inputString += (char)inByte; //add the character from bluetooth to string } } //end code for reading in communication //start code to check for OK communication if ((inputString == "OK" || inputString == "ok" || inputString == "Ok") && returnFlag == true) { Serial1.println("Have fun sending Sparki movement commands!"); delay(500); oKSent = true; //exit the OK while loop } //end code to check for OK communication else //send instructions once a second { Serial1.println("Sparki expects to receive communication that are"); Serial1.println("movement commands (Forward, Right, Left, Stop)"); Serial1.println("separated by spaces."); Serial1.println("Do not send Sparki more than ten commands at a time."); Serial1.println("The line below is an example of valid communication."); Serial1.println("Forward Right Forward Left Forward"); Serial1.println("Type OK and press Send or Return to continue."); Serial1.println();//empty line to separate messages delay(2000); } } //end code for instructions } |
- Change the commArray variable from “String” to “char”
- Change the Serial1.println( ); commands so that they tell the user to send a single character (‘F,’ ‘R’ or ‘L’) instead of the words “Forward,” “Right” or “Left”
- Change the line-
1 |
commArray[arrayCounter] += (char)inByte; |
1 |
commArray[arrayCounter] = (char)inByte; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
#include <Sparki.h> // include the sparki library String inputString; //make an empty String called inputString boolean returnFlag; //flag to check for carriage return boolean oKSent; //flag to check for OK communication char commArray [10]; //array to store communication int arrayCounter = 0; //integer to count through commArray void setup() { Serial1.begin(9600); } void loop() { instructions(); if(oKSent){ readComm(); makeMove(); } } void makeMove(){ for(int i = 0; i <= 9; i++) { if(commArray[i] == 'f' || commArray[i] == 'F') { sparki.moveForward(); delay(1000); sparki.moveStop(); } else if (commArray[i] == 'r' || commArray[i] == 'R') { sparki.moveRight(90); } else if (commArray[i] == 'l' || commArray[i] == 'L') { sparki.moveLeft(90); } else if (commArray[i] == 's' || commArray[i] == 'S') { sparki.moveStop(); delay(1000); } } void readComm() { while (Serial1.available()) { int inByte = Serial1.read(); if ((char)inByte == 'n') { returnFlag = true; arrayCounter = 0; } else { //here is where the code differs a lot from the previous code if(inByte == 32) //if it's a blank space { arrayCounter ++; //increment array counter to store in new array space } else { //add the character to the arrayCounter space in commArray // commArray[arrayCounter] += (char)inByte; //this line changed to commArray[arrayCounter] = (char)inByte; } } } } void instructions() { //Start code for instructions while (oKSent == false) { //start code for reading in communication while (Serial1.available()) { if (returnFlag) { inputString = ""; returnFlag = false; } int inByte = Serial1.read(); if ((char)inByte == 'n') { returnFlag = true; } else { inputString += (char)inByte; //add the character from bluetooth to string } } //end code for reading in communication //start code to check for OK communication if ((inputString == "OK" || inputString == "ok" || inputString == "Ok") && returnFlag == true) { Serial1.println("Have fun sending Sparki movement commands!"); delay(500); oKSent = true; //exit the OK while loop } //end code to check for OK communication else //send instructions once a second { Serial1.println("Sparki expects to receive communication that are"); Serial1.println("characters for movement commands separated by spaces."); Serial1.println("(F for forward, R for Right, L for Left, S for Stop)"); Serial1.println("The line below is an example of valid communication."); Serial1.println("F R F L F S"); Serial1.println("Type OK and press Send or Return to continue."); Serial1.println();//empty line to separate messages delay(2000); } } //end code for instructions } |
- Clear the commArray once all the movement commands have been executed by using the memSet command-
1memset(commArray, 0, sizeof(commArray)); //clear out commArray
- Optional- Make Sparki occasionally send a “Hello? I’m waiting for a command.” message if the user doesn’t communicate with Sparki often enough
- It might also be useful to send a “Command not recognized.” or “I’m confused!” message when Sparki receives a command that it can’t find in its list of movement commands so the user knows that whatever they typed into the serial Terminal isn’t understood by Sparki