The offboard system uses the raspberry pi as the base station to send and receive signals from the iPads over the network interface and process the messages and send control packets to the game master Xbee.
This Xbee is connected to the raspberry pi using a slice of pi interface board which sends and receives serial signals from the serial GPIO TX and RX pins on the raspberry pi to the UART data in and UART data out pins on the Xbee.
In the post Laser Detection it was discussed how to set up a detector
circuit and how the Arduino would recognise when the LaserBot was hit through
the use of an interrupt. That was only for one detector circuit. However, three
detector circuits are wanted on the LaserBot to make the game more interesting
– more targets to shoot at, different points for the different targets etc.
PROBLEM ENCOUNTERED WITH ONE INTERRUPT
At first, only one interrupt was going to be used for all
three detector circuits. This caused a problem in detecting which target had
been hit as the interrupt only notifies the Arduino that it has been hit
but not which target has been hit. The idea was then to have an output
coming off each circuit which would then have its own individual port on the
Arduino. When the interrupt said that the Arduino had been hit, the Arduino
could then check the three different ports and see which ports state had
changed. This, however, did not work as the interrupt joined all three circuits
together, causing all three circuits to change state when they were hit.
Therefore, it was decided to use the two
interrupts available on the Arduino. Two detector circuits would be connected
to one interrupt, and the other circuit would be connected to the other
interrupt. This meant that the Arduino could differentiate between two
circuits, but not three. So, the user could get two different scores for
hitting targets, rather than three different scores, which is not a big loss in
terms of flexibility for the game.
The Tamiya tank systems, gearbox, tracks and platforms all came with instructions and although they had many small parts and were time consuming to assemble were otherwise relatively straightforward to assemble and test.
Further research into the game's communication systems led to the discovery of the OSC (Open Sound Control) protocol. This is often used instead of MIDI in electronic musical instruments to allow communication and control between different devices.
Much of the inspiration for this section of the project came from Pete-O's excellent work on OSC and the Arduino which can be found here.
For this project we used TouchOSC on the iPad, as there are two iPads available for use within the group (freeing up iPhones and iPod touches for possible camera use). This app costs £3, and includes a free interface designer for Windows. Using this designer, an application was developed to send robot control signals from the iPad, this interface can be seen below.
iPad interface for control - note space at the top for future game messages
Once run, the app was configured with host IP address and port of the Processing application which is discussed later.
Processing is an IDE and language that builds on Java, but with a simpler graphics programming model. This is ideal for us, as it works very well alongside the Arduino development environment, which was developed on the same interface. This makes it relatively easy, and well documented online to get an Arduino talking to the Processing sketch. In addition, there is an OSC library available, allowing us to parse and process OSC messages received over a local network. The OSC library has been developed by Andreas Schlegel, and is available here.
An Arduino is used to control each robot. Through the use of XBees, a signal will be sent from Processing, which the robot Arduino will pick up. The packet that is sent from Processing is in the following format: < - indicates the start of the packet F or f - sets whether the laser is on or off XX - two numbers that determine the position of servo x XX - two numbers that determine the position of servo y F, B or S - determines left motor state F, B or S - determines right motor state > - indicates the end of the packet For the Arduino to receive the packets, the Arduino reads its serial port. While there is information available on the serial port, it stores the incoming bytes into an array. The code for this can be seen below.
while(Serial.available() > 0){//look for Serial data
int incoming = Serial.read();//read and store the value
instruction[i] = incoming; //store the instruction in the array
There are then checks put into place to see whether or not what was sent to the Arduino is in the correct packet format. If the Arduino cannot find the start and end delimiters of the packet (< and >, respectively) it ignores the received information.
//loop round the instruction array (expecting 9 characters)
for (j = 0; j<9; j++)
{
//get the coordinates for the motor
if ((instruction[j] == '<') && (instruction[j+8] == '>'))
{
If the incoming packet does have the start and ending characters, the Arduino can parse the packet. The string format is known so it is as simple as comparing each character to what you expect. Firstly, the servo instructions are dealt with. There should be 4 numbers in the packet - two for servo x and two for servo y. Since these numbers arrive as characters, they need to be concatenated into a String and then converted to an Integer. The code for this can be seen below. Once the Integer has been retrieved, the number is written to the correct servo.
//concatenate the two strings for x coordinates together
stringXCoord += instruction[j+2];
stringXCoord += instruction[j+3];
//make the string an integer
intXCoord = stringXCoord.toInt();
servoX.write(intXCoord); //write to the servo
//concatenate the two strings for y coordinates together
stringYCoord += instruction[j+4];
stringYCoord += instruction[j+5];
//make the string an integer
intYCoord = stringYCoord.toInt();
servoY.write(intYCoord); //write to the servo
Next, the laser is dealt with. If the laser character is 'F', then the laser should be turn on else if it is 'f' then it should be turned off.
//turn laser on
if (instruction[j+1] == 'F')
{
digitalWrite(laser, LOW);
}
//turn laser off
if (instruction[j+1] == 'f')
{
digitalWrite(laser, HIGH);
}
The motors on the robot are next to be parsed. The expected characters are 'F', 'B' or 'S'. 'F' means that the motor should move forward, 'B' means that the motor should go backwards and 'S' means the motor should stop moving. There is one character for the left motor and one for the right. The code for the motors can be seen below.
//control motors on robot - left motor forward
if (instruction[j+6] == 'F')
{
digitalWrite(leftMotor1, LOW);
digitalWrite(leftMotor2, HIGH);
}
//control motors on robot - left motor stop
if (instruction[j+6] == 'S')
{
digitalWrite(leftMotor1, LOW);
digitalWrite(leftMotor2, LOW);
}
//control motors on robot - left motor backward
if (instruction[j+6] == 'B')
{
digitalWrite(leftMotor1, HIGH);
digitalWrite(leftMotor2, LOW);
}
//control motors on robot - right motor forward
if (instruction[j+7] == 'F')
{
digitalWrite(rightMotor1, HIGH);
digitalWrite(rightMotor2, LOW);
}
//control motors on robot - right motor stop
if (instruction[j+7] == 'S')
{
digitalWrite(rightMotor1, LOW);
digitalWrite(rightMotor2, LOW);
}
//control motors on robot - right motor backward
if (instruction[j+7] == 'B')
{
digitalWrite(rightMotor1, LOW);
digitalWrite(rightMotor2, HIGH);
}
Finally, variables need to be reset. The variable i used for storing the incoming serial into an array is set to -1 and then incremented to get back to 0, as resetting back to 0 would not work.
//reset variable for instruction array
i = -1;
}
}
//increment counter for instruction array
i++;
//reset variables used
stringXCoord = "";
stringYCoord = "";
intXCoord = 0;
intYCoord = 0;
}
}
All of the code given was in the void loop() method. For the code to work, all variables were stated at the start of the sketch and any libraries needed were included.
#include <Servo.h>
char instruction [9]; //instruction sent to arduino
int i = 0; //index for instruction array
int j = 0; //index for for loop
String stringXCoord = "";
int intXCoord; //x coordinate for motor
String stringYCoord = "";
int intYCoord; //y coordinate for motor
Servo servoX; //servo x
Servo servoY; //servo y
//pin for laser and LDR
int laser = 13;
//pin numbers for the motor on the robot
int leftMotor1 = 11;
int leftMotor2 = 12;
int rightMotor1 = 9;
int rightMotor2 = 10;
In void setup(), pins have to be set as either an input or output, and servos need to be attached.
void setup(){
//init Serial library (make sure Processing is sending data at the same baud rate)
Serial.begin(9600);
servoX.attach(5);
servoY.attach(6);
pinMode(sensor1, INPUT);
pinMode(laser, OUTPUT);
pinMode(leftMotor1, OUTPUT);
pinMode(leftMotor2, OUTPUT);
pinMode(rightMotor1, OUTPUT);
pinMode(rightMotor2, OUTPUT);
}
Any extensions to the packet sent between the robots can easily be integrated. The indices of any arrays will need to be changed, and if statements will need to be added, which is relatively easy to do, showing that the code is very flexible in terms of future work.
Firstly, the laser needed to be tested to see if it would work. On the TTL laser, there is a polarized 4-pin connector with the following connections:
Red wire:5-12 V DC input
Black wire: GND
Green wire: 10k pull-down (aka GND)
White wire: active low TTL input (3.3 V or 5 V logic)
The laser was tested by firstly just turning the laser ON and leaving it on. This was done by connecting the red wire to a power source, the black wire to GND, the white wire to GND and leaving the green wire unconnected. This successfully turned the laser on.
TESTING LASER WORKS WITH ARDUINO
The laser was then tested with the Arduino. The white wire was connected to a TTL output on the Arduino (Port 13), the red wire was connected to 5V and the black wire was connected to Gnd as shown in the diagram below. Again, the green wire was left unconnected.
Arduino Laser Connections
The Arduino was given power and the basic sketch "Blink" was downloaded to the board. Once downloaded, the laser successfully started blinking in accordance with the sketch. This shows that the laser can easily work with the Arduino.
The testing for this laser was found at this site.
Laser Detection
LDR
To detect a laser, a light dependent resistor (LDR) is needed. An LDR is a device which has a resistance that varies according to the amount of light falling on its surface. A typical LDR can be seen pictured below, along with its circuit diagram symbol.
LDR and circuit symbol
The LDR that was chosen to go with the TTL Laser Module was the Mini Photocell, as this was suggested from the manufacturer. The photocell can be seen below.
Mini Photocell
DETECTION CIRCUIT
An LDR can be set up in two ways:
The LDR is activated by darkness
The LDR is activated by light
For LaserBots, a laser is fired and the LDR is meant to detect when the laser hits it. Therefore, the LDR needs to be activated by light. The circuit for this can be seen below:
LDR circuit
When light hits the LDR, the LED will light up. The variable resistor is used to fine tune the amount of light needed to activate the LDR.
A similar circuit to the one pictured above (resistor values were different) was built on a breadboard and the variable resistor was used to tune the LDR so that only the high intensity laser beam activated the LED and not the background light from the room. The circuit was powered by connecting it to an Arduino, along with a laser. A video of this circuit working can be seen below.
As can be seen, when the laser moves over and hits the LDR, it switches the transistor and turns the LED on.
ARDUINO CODE
SIMPLE LASER DETECTION
Now that the laser and detection circuit has been tested to see that both work, the next stage is to get the Arduino involved. The Arduino should be able to turn the laser on and off. Firstly, the pin that the laser is connected to can be given a name, for example, laser. This pin can then be set as an output, which will tell the laser to go either high or low depending on which command the Arduino writes to it. For this first simple set up of code, the laser is set to be low. The pin that the LDR is connected to is set up in the same way. It is given a name (LDR) and is assigned a pin mode (this time it is set to input, as data will be received from the LDR). For this circuit, the laser is connected to pin 8 and the LDR is connected to pin 7, but any pin could have been chosen. The code can be seen below.
/*
int LDR = 7; //LDR attached to pin 7
int laser = 8; //Laser attached to pin 8
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
// make the LDR's pin an input:
pinMode(LDR, INPUT);
//make the laser's pin an output:
pinMode(laser, OUTPUT);
digitalWrite(laser, LOW);//turn laser on
}
Now that the pins have been set up, code can be written to interact with the detector circuit that has been built. When the LDR is hit with the laser, the output changes from high to low. This change can be picked up by the Arduino by doing a digital read of the pin. A digital read reads the value from a specified digital pin, either HIGH or LOW. If the value read is LOW, the Arduino can state that it has been hit, else if it is HIGH it won't do anything, as can be seen in the following code.
// the loop routine runs over and over again forever:
void loop() {
// read the input pin:
int hitState = digitalRead(LDR);
//LDR goes low when it has been hit
if (hitState == 0)
{
Serial.println("HIT");
delay(2000); // delay in between reads for stability
}
This code can now be put together and uploaded onto the Arduino. The Arduino and detector circuit should be set up as follows. INSERT PIC Once everything is set up, the Arduino was kept connected to the computer and a Serial monitor was opened. When the laser hit the LDR, on the Serial monitor "HIT" was printed. The Arduino successfully works with the laser detection circuit.
USING INTERRUPTS
If the robot was only detecting whether or not it had been hit, the code shown above would be fine. However, the robot is going to be processing lots of other code (controlling servos, motors, lasers etc) and so the above code is not sufficient, as it only checks if it has been hit once every turn of the loop. This could cause the robot to miss detecting that it has been hit.
To overcome this problem, interrupts can be used. An interrupt is a signal to the processor emitted by hardware or software indicating an event that needs immediate attention, which in this case is the LDR stating that it has been hit. There are only two external interrupt pins on the Arduino Uno, INT0 and INT1, and they are mapped to Arduino pins 2 and 3. The interrupts can be set to trigger on RISING or FALLING signal edges, or on low level. It was decided that the interrupt should occur on the FALLING signal edge rather than on low level. This is because it means that the user will have to move the laser off the LDR before they can hit the robot again, making the game slightly harder. Otherwise, the user could just leave the laser pointing on the LDR and get a huge score.
The code was changed to use interrupts instead of a digital read. For interrupts to work, the interrupt library needs to be included in the code, therefore at the top of the program before anything else this line of code was added:
#include "avr/interrupt.h"
Firstly, the pin that the LDR was on was changed from 7 to 2 (as pin 2 has an interrupt attached to it). In the setup method, the following code was added to enable the interrupt and set the interrupt to trigger on a falling edge.
An interrupt service routine (ISR) then needs to be written. An ISR is the code that is run when the interrupt is triggered. For the moment, the Arduino will just print out that it has been hit.
//interrupt service routine for when the LDR is hit
ISR(INT0_vect)
{
Serial.println("HIT INTERRUPT");
}
In the main loop of the program, the digital read is removed, as that is no longer needed. To get the program to still do something for the interrupt to interrupt, the Arduino will just print out that it is waiting for the interrupt. The whole code now looks like this:
int LDR = 2; //LDR attached to pin 2 (as pin 2 has an interrupt on it)
int laser = 8; //Laser attached to pin 8
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
// make the LDR's pin an input:
pinMode(LDR, INPUT);
//make the laser's pin an output:
pinMode(laser, OUTPUT);
sei(); //Enable global interrupts
EIMSK |= (1 << INT0); //Enable external interrupt INT0
EICRA |= (1 << ISC01); //Trigger INT0 on falling edge
digitalWrite(laser, HIGH);//turn laser on
}
// the loop routine runs over and over again forever:
void loop() {
//print something so program has something to do
Serial.println("Waiting for interrupt");
delay(1000); //wait one second
}
//interrupt service routine for when the LDR is hit
ISR(INT0_vect)
{
Serial.println("HIT INTERRUPT");
}
Running the code and watching on a serial monitor, the program outputs "Waiting for interrupt" every second until the interrupt is called, in which case it prints "HIT INTERRUPT".
UPDATING SCORES AND USING MILLIS
Now that the code works with interrupts, more functionality can be added. A score can be added into the code, so that every time the robot is hit, a score is incremented. To stop a user from continually hitting the robot and gaining a large score very quickly, an interval can be included to stop incrementing the score until 5 seconds has passed between hits. Finally, rather than using delays in the code which hold the whole program up, a function called millis() can be used. It is a command that returns the number of milliseconds since the Arduino board started running its current program. An example of using millis() is given in the Arduino examples, callled "Blink without Delay". Combining all of the above, the final code looks like the following:
#include "avr/interrupt.h"
int LDR = 2; //LDR attached to pin 2 (as pin 2 has an interrupt on it)
int laser = 8; //Laser attached to pin 8
int score = 0; //score of the robot
int scoreFront = 10; //score of hitting the LDR
//introduce 5 second interval after hit before another hit can occur
int interval = 5000;
long lastBlinkTime = 0; //variable used with millis
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
// make the LDR's pin an input:
pinMode(LDR, INPUT);
//make the laser's pin an output:
pinMode(laser, OUTPUT);
sei(); //Enable global interrupts
EIMSK |= (1 << INT0); //Enable external interrupt INT0
EICRA |= (1 << ISC01); //Trigger INT0 on falling edge
digitalWrite(laser, HIGH);
}
// the loop routine runs over and over again forever:
void loop() {
//make program do something
digitalWrite(laser, HIGH);
}
//interrupt service routine for when the LDR is hit
ISR(INT0_vect)
{
unsigned long hitMillis = millis();
//if there has been more than 5 seconds since the last hit
if ((hitMillis - lastBlinkTime) > interval)
{
lastBlinkTime = hitMillis;
//increment score
score = score + scoreFront;
Serial.println("Hit Interrupt");
Serial.println(score);
}
}
Running this code, when the LDR is hit, the ISR is called and "Hit Interrupt" along with a score is printed, for example 10 for the first hit. When the user tries to hit the LDR again, nothing happens until 5 seconds has passed. The user hits the LDR again and now the Arduino prints out "Hit Interrupt" with a score, now equal to 20. This concludes the code that is needed for laser detection.
The Tamiya double gearbox can be controlled using the digital logic signals from the Arduino's 5v output. However there was some concern about powering the motors directly from the output ports as they draw a lot of current and the Arduino is going to be used to drive multiple systems.
In order to overcome this problem a H- Bridge motor driver (in this case a L293D chip) was used. This enabled the use the logic signals from the Arduino while powering the motors from an external power source.
Breadboard Layout
The motors seen in the diagram above are connected to the left and right sides of the Tamiya double gearbox in order to drive the tracks on the respective sides of the robot. The power source is independent from the Arduino power source and is used to provide power to the two motors, the two servos and the laser. In this case 4 AA batteries are used to provide 6V. It is yet to be tested how long these will power the robot for.
One issue noticed was that if the external power was removed or turned off before the logic signals the motors would continue to attempt to run using the power from the logic circuit. So it should be ensured the arduino isnt sending motor signals without power being supplied to pin 8.
IC Circuit diagram
As seen in the above diagram channels 1 and 2 are used for motor 1 which controls the left track. Therefore in order to make the left track go forward pin 2 (channel 1 input) is set high and pin 7 is set low. Similarly if pin 7 is set high and pin 2 set low the motor will reverse. If the two pins are the same, both high or both low then the motor doesn't move. Channels 3 and 4 are used in the same way to control motor 2 controlling the track on the right side of the robot.
The Arduino code to test the motors was therefore extremely simple and just consisted of setting each of the 4 pins either high or low for 1.5 seconds depending on which direction the user wants the robot to move, in between each test the robot is set to stop for 1.5 seconds before moving onto the next instruction.
Two micro servos were sourced from previous projects, and the prototype system was set up with the laser as can be seen below.
The laser is attached to the top y axis servo, with that servo itself attached to the x axis servo underneath. These are then controlled and powered through the Arduino. The red and black wires of the servos are connected to 5V and ground respectively, with the white (yellow in the diagram below) wire connected to the digital PWM port used for control. In the prototype, pins 9 and 10 on the Arduino are used.
Due to a delay in the ordering of parts, it was decided that more research into the laser used for the firing device was needed. The laser that was going to be ordered needed a driver circuit built for it so instead of having to create this, it was decided that another laser would be ordered instead.
Laser Module
The laser that is now being ordered is the Laser Module - Red with TTL Control from proto-pic.co.uk. It is a basic laser card module with circuitry built in so that it can be turned on/off with a TTL signal, making it much easier to use with an Arduino.
The Onboard Video system will capture a live feed from each robot and display both feeds on a screen on the off-board device. The video stream should be good enough quality to be able to facilitate both the movement of the device and determine how much to adjust the fine firing control.
Chosen Design - iWebCamera - £3.00
Provides a virtual webcam to your computer by connecting to an iPhone/Ipod touch running iWebcamera. This will provide us with two webcam streams on the raspberry pi, one each from a iphone/ipad on each robot.
The platform of the device will provide a mobile platform to base all the on-board electronics. It should be able to be maneuvered relatively easily as well as being big enough to hold all of the electronics equipment and associated power supplies. The device should be able to be controlled using a number of digital outputs from the Arduino. The power needed for the device should be able to supplied using an on-board battery although this may be a different battery from the one used to power the electronics.
The off-board system refers to the scoring system of the game and the smart phone app that
will allow the user to drive the robot.
Scoring System
When a robot
fires at the other robot and hits a target, they will be awarded a point. The
point value will depend on how easy or hard the target was to hit. When the
sensor is hit, a message will be sent to the main game master to increment the
score of the robot who shot the target. This score will then be displayed on a
screen in the form of a GUI. The figure below demonstrates this.
Offboard System and Robots
Smart Phone App
An app will be
created to allow the user to control the robot. It will have buttons for the
movement of the robot (left, right, forward, backward) and it will also have
buttons to control the firing device (pan left/right, pan up/down, fire).
This system involves controlling the robots through a
smartphone and notifying the games master when game events happen, such as a
robot being hit, game start/stop etc.
OUTLINE OF COMMUNICATIONS LINKS REQUIRED
Different
communication options and configurations were considered in terms of cost and
ease of implementation.
The firing system is what the robot uses to shoot at the other robot. A robot will have one firing device and multiple targets which will detect the shots fired.
Design
The firing device will be made from a laser diode. A laser diode has a small emission angle meaning that it is very accurate. To detect the laser, a photo transistor will be used. This detects the light and converts it to an electrical signal. The laser diode and photo transistors will be connected to the Arduino, as the Arduino is very good at receiving input from a variety of sensors and also controlling emitters.
This system
should allow the user to move the firing device in small increments after
positioning the robot. An illustration
of the movement can be seen below.
This movement can either be on the x axis or on the y axis, turning the
device horizontally or vertically.
FINE CONTROL OF FIRING DEVICE
Using this
system it will be possible to alter difficulty by limiting range of movement
therefore forcing user to move robot, or speed of movement.
A functional specification has been drawn up in order to clearly define our aims and objectives for this project. This way, we can prioritise time effectively so that the most important objectives can be achieved first, before moving onto secondary ones.
Diagram of whole system
Below can be seen the basic, intermediate and advanced objectives that have been drawn up.
The Raspberry Pi and theArduinoare two very different devices each suited to different activities.
The Arduino is an open-source
electronics prototyping platform. It can receive input from a variety of
sensors and can affect surroundings by controlling lights, motors and other
actuators. It is low power and also has serial communication capability. It is
programmed using the Arduino programming language (based on Wiring) and the
Arduino development environment (based on Processing). The programming language
is very similar to C/C++.
The Raspberry Pi is a single-board
computer that is small in size (85.60 mm × 53.98 mm) and was
developed to aid the teaching of basic computer science in schools. It uses the
Linux operating system. The Pi has a Broadcom system on a chip which includes
an ARM 700 MHz processor, a VideoCore IV GPU, and 256 Mb of RAM. There is not a
built in hard disk but it has an SD card slot.
Arduino (left) and Raspberry Pi (right)
Our embedded systems class requires us to design a 'gadget' using either of these devices. A selection of ideas were put forward: