Get Help
Computer Inputs
Introduction
In this lesson we will learn more about how to enable Sparki to communicate with a computer, both from the computer to the robot (to send commands), and from the robot to the computer (to receive data from sensors and robot status). Before starting with this lesson, it’s strongly recommended that you read and understand the concepts in the Using USB Serial and Bluetooth Communications lesson.What You’ll Need
- A Sparki.
- The Bluetooth module (included with the Sparki).
How It Works
Sparki is an autonomous robot. This means that we can store a program on it’s non-volatile memory and he will act according to that program’s instructions, without any help from the outside world. This is what we have been doing in all the previous lessons. That way of using Sparki has a some advantages:- It’s simple: there is just one program, and it runs inside the robot once uploaded.
- We don’t rely on anything else than a Sparki once it has been programmed.
- Batteries last long if there is no wireless communication system active in the robot (like the Bluetooth module, for example).
- When our application needs more processing power.
- When we want Sparki to interact with a graphical user interface.
- When we need to exchange data between the robot and the outside world (for example from the Internet).
- When we want the robot to interact with external sensors or with the environment itself.
- When we need to coordinate the work of more than one robot.
First Example
Let’s start by a simple serial remote control example, where we just send some simple commands to the robot using its virtual serial port through the USB cable . Then we can always modify the example to work with the Bluetooth Module. Please remember to check that the batteries are properly connected (and charged!). And as we are going to use the motors here, please check that the On/Off Switch is on. Another important thing to take care of when playing with the robot’s motors is to be careful not to be working over a table. A fall from that table could permanently damage your Sparki. Here is the initial code:
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 |
#include <Sparki.h> // include the sparki library void setup() { } void loop() { if (Serial.available()) { int inByte = Serial.read(); Serial.println((char)inByte); switch ((char)inByte) { case 'w': sparki.moveForward(); break; case 'd': sparki.moveRight(); break; case 'a': sparki.moveLeft(); break; case 'x': sparki.moveBackward(); break; case 's': sparki.moveStop(); break; } } } |
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 |
#include <Sparki.h> // include the sparki library void setup() { } void loop() { if (Serial.available()) { int inByte = Serial.read(); Serial.println((char)inByte); switch ((char)inByte) { //Actions: case 'w': sparki.moveForward(); break; case 'd': sparki.moveRight(); break; case 'a': sparki.moveLeft(); break; case 'x': sparki.moveBackward(); break; case 's': sparki.moveStop(); break; //Sensor readings: case 'p': Serial.print("ping="); Serial.println(sparki.ping()); break; case '0': Serial.print("edgeL="); Serial.println(sparki.edgeLeft()); break; case '1': Serial.print("lineL="); Serial.println(sparki.lineLeft()); break; case '2': Serial.print("center="); Serial.println(sparki.lineCenter()); break; case '3': Serial.print("lineR="); Serial.println(sparki.lineRight()); break; case '4': Serial.print("edgeR="); Serial.println(sparki.edgeRight()); break; } } } |
Asynchronous Events
And what about sending information from the robot in an asynchronous way? For example, why not trigger an event when a sensor reading reaches a threshold? That’s easy to do: just add the code to test that sensor, and when the comparison with the threshold becomes true, tell it to the remote computer:
1 2 3 4 |
if (sparki.edgeLeft() < edgeThreshold) //if an edge is detected, send this message! { Serial.println("leftEdge!"); } |
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 |
#include <Sparki.h> // include the sparki library int edgeThreshold = 200; void setup() { sparki.servo(SERVO_CENTER); } //Send an asyncronous event to fire an alarm on the computer side: void processEvents() { if (sparki.ping() < 5) //If the robot is going to crash against and obstacle, send this message! { Serial.println("obstacle!"); } if (sparki.edgeLeft() < edgeThreshold) //if an edge is detected, send this message! { Serial.println("leftEdge!"); } if (sparki.edgeRight() < edgeThreshold) //if an edge is detected, send this message! { Serial.println("rightEdge!"); } delay(20); } void loop() { //Process the asyncronous events: processEvents(); //Receives commands from remote computer: if (Serial.available()) { int inByte = Serial.read(); Serial.println((char)inByte); switch ((char)inByte) { //Actions: case 'w': sparki.moveForward(); break; case 'd': sparki.moveRight(); break; case 'a': sparki.moveLeft(); break; case 'x': sparki.moveBackward(); break; case 's': sparki.moveStop(); break; //Sensor readings: case 'p': Serial.print("ping="); Serial.println(sparki.ping()); break; case '0': Serial.print("edgeL="); Serial.println(sparki.edgeLeft()); break; case '1': Serial.print("lineL="); Serial.println(sparki.lineLeft()); break; case '2': Serial.print("center="); Serial.println(sparki.lineCenter()); break; case '3': Serial.print("lineR="); Serial.println(sparki.lineRight()); break; case '4': Serial.print("edgeR="); Serial.println(sparki.edgeRight()); break; } } } |
Using Bluetooth Instead of the USB Serial
One of the main uses of these kind of programs, is to control it remotely through a wireless connection. As you may already know, one of the best ways to connect to Sparki wirelessly is by using the The Bluetooth module. But from the Using USB Serial and Bluetooth Communications lesson you will remember that any program that uses the Serial port nees some minor modifications to work with the Serial1 port instead (Serial1 is where the Bluetooth module is connected, in Sparki’s Expansion Port). Here we suggest a way of defining an alias for the serial port, called just “serial“, so you can then select Serial or Serial1 with just one line change in the #define at the beginning of your program:
1 2 |
#define serial Serial //#define serial Serial1 |
1 2 3 4 5 |
void setup() { serial.begin(9600); // necessary for the Bluetooth. sparki.servo(SERVO_CENTER); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
void loop() { //Process the asyncronous events: processEvents(); //Receives commands from remote computer: if (serial.available()) { int inByte = serial.read(); serial.println((char)inByte); switch ((char)inByte) { //Actions: case 'w': sparki.moveForward(); break; [...] |
Creating a Parsable Output for Multiple Sensor Readings
In the previous examples, the phrases returned by the robot were easy to read by a human, but not that easy to be parsed by a computer. So, if we want something more advanced, like reading the sensors values to be used by the high level program in our remote computer, we may prefer to format a bit the returned data from the robot. In the following example we are doing exactly that. Another change that you will see in he following code is that now, a single command (with the character “r”, from “read”) is used to read all the robot sensors (well, not all, but all the sensors that matters to us in this example):
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 |
#include <Sparki.h> // include the sparki library //#define serial Serial #define serial Serial1 void setup() { serial.begin(9600); // necessary for the Bluetooth. sparki.servo(SERVO_CENTER); } void loop() { //Receives commands from remote computer: if (serial.available()) { int inByte = serial.read(); serial.println((char)inByte); switch ((char)inByte) { //Actions: case 'w': sparki.moveForward(); break; case 'd': sparki.moveRight(); break; case 'a': sparki.moveLeft(); break; case 'x': sparki.moveBackward(); break; case 's': sparki.moveStop(); break; //Sensor readings: case 'r': serial.print("<p="); serial.print(sparki.ping()); serial.println("=p>"); serial.print("<0="); serial.print(sparki.edgeLeft()); serial.println("=0>"); serial.print("<1="); serial.print(sparki.lineLeft()); serial.println("=1>"); serial.print("<2="); serial.print(sparki.lineCenter()); serial.println("=2>"); serial.print("<3="); serial.print(sparki.lineRight()); serial.println("=3>"); serial.print("<4="); serial.print(sparki.edgeRight()); serial.println("=4>"); break; } } } |
<p=20=p>
Where 20 is the reading (20 centimeters in this case) and the p identifies the ping sensor. Of course that all this stuff can be done in a lot of different ways, but this one is very simple, and this particular program will be the one that we are going to use for the initial basic integration between Sparki and Android™ devices when working with multiple sensors. Finally, please note that if you want to read other sensors (like the accelerometer, or the magnetomer, for example), you just need to add a small and simple block of code (try it!).