Introduction: Swarmbots: Autonomous Arduino Cars That Play Musical Chairs

Our intention with this project was to merge two cutting-edge fields of technology: autonomous vehicles and swarmbots. In a partnership with the Fremont Academy for Technology and Design’s Femineer students, ten members of the Pomona College Electronics class (Spring, 2016) assembled four autonomous vehicles that were able to play a game of “musical chairs.”
The game is deceptively simple. While music plays, the cars circle around a track. When the music stops, the cars turn inside the arena and look for a “chair” - a black spot. Once they find the spot, they stop. In theory, there would be n-1 “chairs” and the remaining car would be taken out of the arena, starting the next round.

While seemingly simple, this game proved to be an engineering feat! First, the cars must be assembled (either from a kit, or deconstructing a ready-made RC car). Second, they must be outfitted with the proper sensors and controller. The vehicles must have at least three sensors: a line tracker (to follow the track at the circumference of the arena, and to identify a chair), a sound sensor (to know when to start moving and when to turn in), and an infra-red sensor (for collision avoidance). Our cars used an Arduino Rev3 controller. Each of us used a different kit car, but for the purposes of this Instructable, we will highlight one (without a doubt, the best-looking car).

Parts List:

Car Body (multiple options)

Arduino Uno

H-bridge

9-Volt Battery

4(8) AA Batteries

Sound Sensor

3 Infrared Line Sensors (two options, both work well)

Range Sensor (Infrared or ultrasonic)

This specific car was built from a kit that had neither a brand nor instructions, so the parts that were included in the kit were used to build the black box that connects to the treads.
We placed the breadboard and battery pack on top of the black box and looped the connecting wires through the inside of the box to reach the motors. The motors were placed on the inside walls of the box and drove the white “adapters” that connected to the tank treads

Fremont Academy provided us with the tank treads. Since the treads did not originally connect well to the motors, we 3D printed the white adapters. In addition, to make the tank treads move smoothly, we glued pieces of rubber in the rifts of the tank.

We also 3D printed a tetrahedron shape to serve as the cover for the tank. This allowed us to put the infrared detector on the front of the tank to be able to detect the distance of cars in front of us so that we could avoid collisions. We put the three line followers underneath the hood of the tetrahedron cover. Finally, we used the opening in the back to be able to connect and disconnect the 9V battery as needed.

Step 1: Put Together Your RC / Kit Car

It's important to choose a ready-made RC car that (1) allows you enough space to put your controller and wires and (2) is tough enough to be deconstructed and put together many times. We suggest using an Arudino kit car (like the one pictured here) because it gives you the freedom to customize everything: where you put sensors, how many motors you'd like, weight distribution, etc. Every kit car is different and most come with instructions. Putting the car together is the easy part!

If you're working from a ready-made RC car, take off the cover to expose the inner control box. Then take it out and replace it with your Arduino and breadboard. More on this in the next steps...

Step 2: Installing Your H-Bridge

H-Bridges are a great component to use when building autonomous cars. A H-Bridge allows us to apply a voltage across a load in either direction, meaning it gives us the ability to run the DC motors for our cars both forwards and backwards, allowing us to change the direction our car is traveling without making it turn in a full circle (i.e.: we can simply drive forwards or drive in reverse).

Before we actually use the H-Bridge, let’s get familiar with how exactly they work. H-Bridges have four switches, two on one side parallel to two on the other side. In the middle of these four parallel switches is our motor, connecting the two sides. When we want to apply voltage one way, we close the top left and bottom right and open the top right and bottom left switches, which allows the voltage to be applied in a clockwise direction. Conversely, if we want to apply a voltage counterclockwise, we must open the top left and bottom right switches, and then close the top right and bottom left switches. Below is a diagram that demonstrates how an H-Bridge actually allows voltage to be applied in two different directions:

(See the third photo)

http://www.hvlabs.com/hbridge.html

So, to apply voltage in a clockwise direction, we close switches A1 and A2 (and open switches B1 and B2). To apply a voltage in a counterclockwise direction, we close switches B1 and B2 (and open switches A1 and A1).

Now let’s talk about how to hook the H-Bridge up to our Arduino and car so that we can get our car moving. First, let’s make sure that we have the right part. The H-Bridge we used in our car looks like this (model number: SN754410):

(See the second photo)

http://www.hobbytronics.co.uk/h-bridge-driver-sn75...

When you put your H-Bridge into your breadboard, take note of what side that small, u-shaped impression is. As you can see in both the picture above, and more clearly in the pin-out diagram below, the side with that divot is the top of the device. Now, let’s move onto talking about how to actually wire up the H-Bridge. Below is a detailed diagram with the pin-out of the H-Bridge we used:

(See the first photo)

http://www.hobbytronics.co.uk/h-bridge-driver-sn75...

The pins are numbered such that 1 is on the top left, 8 is on the bottom left, 9 is on the bottom right, and 16 is on the top right. When you are hooking up your H-Bridge to your Arduino, you are going to want to take note of which pins on the H-Bridge correspond to which pins on you Arduino so that you can write your code successfully. Below is our code, and we can explain how we declared which pins corresponded to which in our code:

// Declare pins that enable steering and driving forwards
and backwards

int driveEn = 8; //enable drive motor

int driveFor = 3; //drive motor forward

int driveRev = 9; //drive motor reverse

int turnEn = 4; //enable turning motor

int turnRight = 11; //turning motor right

int turnLeft = 6; //turning motor left

- This code reflects the following:

o We connected Pin 1 on the H-Bridge to Pin 8 on our Arduino

§ This will enable the first motor

o We connected Pin 7 on the H-Bridge to Pin 3 on our Arduino (Note that Pin 3 on the Arduino is a PWM that allowed us to control the voltage being supplied, but you could just connect it to a digital pin for constant voltage)

§ A HIGH enable will allow the car to drive forward

o We connected Pin 2 on the H-Bridge to Pin 9 on our Arduino (Note that Pin 9 on the Arduino is a PWM that allowed us to control the voltage being supplied, but you could just connect it to a digital pin for constant voltage)

§ A HIGH enable will allow the car to drive backwards

o We connected Pin 9 on the H-Bridge to Pin 4 on the Arduino

§ A HIGH enable will allow the car to turn

o We connected Pin 15 on the H-Bridge to Pin 11 on the Arduino

§ A HIGH enable will allow the car to turn right

o We connected Pin 10 on the H-Bridge to Pin 6 on the Arduino

§ A HIGH enable will allow the car to turn left

// Set all pins to the output or input mode (accordingly)

void setup() {

pinMode(driveEn, OUTPUT);

pinMode(driveFor, OUTPUT);

pinMode(driveRev, OUTPUT);

pinMode(turnEn, OUTPUT);

pinMode(turnRight, OUTPUT);

pinMode(turnLeft, OUTPUT);

v Here, we must declare all pins above as outputs

// Method to make the car drive forwards

void goForwards(){

digitalWrite(driveEn, HIGH); //enables the drive motor

digitalWrite(driveRev, LOW); //makes sure the motor does not rotate reverse

digitalWrite(driveFor, HIGH); //put drive motor foward

return;

}

v Set the driveEn and driveFor pins onto a HIGH enable and the driveRev pin on a LOW enable (disable) to make the car move forwards

// Method to make the car stop

void goStop(){

digitalWrite(driveEn, LOW); //disables the right motor

digitalWrite(driveRev, LOW); //disables the left motor

digitalWrite(driveFor, LOW); //makes sure the motor does not rotate reverse

digitalWrite(turnEn, LOW); //disables the turn motor

digitalWrite(turnRight, LOW); //makes sure the motor does not turn right

digitalWrite(turnLeft, LOW); //makes sure the motor does not turn left

return;

}

- Set all pins to LOW enable (disable) to make the car stop completely

// Method to make the car drive backwards/in reverse

void goBackwards(){

digitalWrite(driveEn, HIGH); //enables the drive motor

digitalWrite(driveFor, LOW); //makes sure the motor does not rotate forward

digitalWrite(driveRev, HIGH); //put drive motor backwards

return;

}

- Set driveEn and driveRev pins to HIGH enable and the driveFor pin to LOW enable (disable) to allow the car to drive backwards

// Method to make the car turn right

void goRight(){

digitalWrite(turnEn, HIGH); //enables the turn motor

digitalWrite(turnLeft, LOW); //makes sure the turn motor doesnt rotate left

digitalWrite(turnRight, HIGH); //rotates turn motor right

return;

}

- Set turnEn and turnRight pins to HIGH enable and the turnLeft pin to LOW enable (disable) to allow the car to turn right

// Method to make the car turn left

void goLeft(){

digitalWrite(turnEn, HIGH); //enables the turn motor

digitalWrite(turnRight, LOW); //makes sure the turn motor doesnt rotate right

digitalWrite(turnLeft, HIGH); //rotates turn motor left

return;

}

- Set turnEn and turnLeft pins to HIGH enable and the turnRight pin to LOW enable (disable) to allow the car to turn left

To make the car do any of these things, you are going to want to call these commands in your void loop () method, which allows you to continually call commands to test your car.

Now, there are several pins left on the H-Bridge that still need to be hooked up. We connected the positive end of motor 1 to Pin 3 on the H-Bridge, and the ground end of motor 1 to Pin 6 on the H-Bridge. We connected the wire for our on-off switch to pin 8 on the H-Bridge. We connected the ground end of motor 2 to Pin 11 on the H-Bridge, and the positive end of motor 2 to pin 14 on the H-Bridge. Finally, we connected Pin 16 to the +5V pin on the Arduino to supply 5 Volts to the H-Bridge. Pins 4, 5, 12, and 13 on the H-Bridge are all ground pins, so we connected pin 13 to ground on the Arduino, then ran a ground line so that multiple things could be connected to ground on the H-Bridge line rather than on the Arduino. Once you hook all of those up, you are ready to go with your H-Bridge!

Step 3: Line Trackers

Materials:

Three line trackers. Types used: VEX Robotics Line Tracker http://www.vexrobotics.com/276-2154.html And SparkFun RedBot Sensor - Line Follower http://www.vexrobotics.com/276-2154.html


Installations:

Regardless of which type you use, the line trackers have three outputs: VCC, GND, and OUT. OUT goes to an analog pin in the arduino, GND goes to ground, and VCC can go to ~+5V.

These “line trackers” consist of a photodiode which essentially feeds the arduino values that correspond with the amount of light it receives. Because we used reflective tape for the track of our game, the line trackers were easily able to distinguish between the ground and the floor of the playing field.

To begin, we first acquired the line trackers from the above-listed websites. We then connected them to the front of our car. Connecting them to the back would be unwise because the car will be too far off of the line by the time that the sensors detect that the car is moving off of the line and attempt to apply a correction. Thus, placing the sensors in the front of the car is the optimal choice for the fastest line tracking reactions. In addition, the right and left line tracker should be placed far enough distance away from the center tracker that when the center tracker is above the line, neither the right or left tracker are above the line.

Note that if you attempt to connect all of the components which need power (line trackers, motors, sound sensors, infrared/ultrasonic sensors etc.) to the 5V source on the Arduino, you are going to have a bad time. The 5V source cannot supply enough current for all of these components and so they will not function properly, if at all. In order to combat this, we connected the line trackers to the +5V of the arduino, and the sound and distance sensors to the 12V (8 1.5V batteries) supply powering the motors. There can be other variations of this setup to ensure that all sensors (and the motors) are supplied sufficient power to function properly, but this setup worked well for us.

After connecting each sensor to a power source, you must connect each sensor to an Arduino pin so that it can read the values of the sensor. They must be connected to an analog pin, not a digital PWM.

Now we need to tell the arduino how to track the line given the inputs of these three line trackers. The main principle of the code is that if the middle sensor sees the line, you are in good shape and the car can go straight. Because of how we placed the right and left sensors, we can determine if the car is veering off the line based on whether or not the right or left sensors begin to detect the reflective tape line. By knowing this, we can then tell the car to apply appropriate corrections to steer the car back towards the line. Depending on which sensor detects the line, you can effectively determine which direction the correction must be applied. For instance, if the right sensor detects the line, the car is veering off of the line towards the left, and a right correction must be applied.

You must also play around with your THRESHOLD value, which marks the difference in sensor readings between the line and the floor. This value will vary depending on the type and reflectivity of the line and floor your car is driving on, the distance of the sensors from the ground, and the kind of sensors that you purchase. For this reason, you must tinker with the code and test the car in order to see which threshold value is best for you. Essentially, you will want to test your sensors by printing their read values in the serial monitor. This debug was implemented in our code below.

The code below is a method specifying how the car line tracks, based on the theory stated above. To implement line tracking in the main loop using this method, it merely needs to be called once.

<p>int centerThresh = 10; <br>int rlThresh = 800;</p><p>void lineTrack(int t) { </p><p>int rightLine = analogRead(A1); <br>int leftLine = analogRead(A2); <br>int centerLine = analogRead(A0); // use these printed outputs in the serial monitor to determine your thresholds <br>Serial.print("Right: "); <br>Serial.print(rightLine); <br>Serial.print(", Center: "); <br>Serial.print(centerLine); <br>Serial.print(", Left: ");   <br>Serial.println(leftLine);</p><p>if (rightLine < rlThresh) { <br>	Serial.println("Turn left, on right sensor"); <br>	turnRight(); <br>	delay(t); </p><p>} </p><p>else if (leftLine < rlThresh) {<br></p><p>turnLeft(); <br>Serial.println("Turn right, on left sensor"); <br>delay(t); </p><p>} </p><p>else if (centerLine < centerThresh) { </p><p>goStraight(); 
Serial.println("Straight"); 
delay(t); </p><p>} </p><p>}</p>

The total code for the sensors implemented all together will be shown at the very end of the instructions.

Because the Arduinos can only handle one primary function in the loop() method, it is not feasible to have it listen for the music WHILE attempting to follow the line. Thus, we had to circumvent the regular rules of musical chairs. Each car was programmed to follow the line for 14 seconds after hearing the initial sound. During those 14 seconds, the sound continued to play. After 14 seconds, both the sound shut off and the cars stopped following the line and turned inwards to find available chairs. This gave the illusion that the cars were responding to the music. While programming the cars to drive for 14 seconds was relatively simple, programming the musical chairs song to play for only 14 seconds was more difficult and required the use of Java programming through Eclipse. Below is the code to make our musical chairs song, the Star Wars Theme song because our game of musical chairs game was played on May the 4th, 2016, play for only 14 seconds.

<p>import objectdraw.*; import java.applet.AudioClip;</p><p>/** * Class: Physics 128 
* Term: Spring 2016 
* Instructor: Janice Hudgings 
* * Project: Musical Chairs Collaboration 
* School: Fremont Academy 
* Group: Femineers 
* *
* -- Plays the musical chairs song (John Williams' Star Wars Opening Theme for * 14 seconds) 
* -- Delay of 1 second from start of applet to beginning of song 
* -- Total run time is 14 seconds *
* * Window Size: 250x250 * * @author Adam Mitchell, Wednesday, 4 May 2016 */ public class MusicalChairsPlayer extends WindowController {
private static final int THRESHOLD_DELAY = 1; // the time to delay for private static final int THRESHOLD_PLAY = 14; // the time to run for
public void begin() {
// Local variables AudioClip music; Boolean playing = false; // whether the music is playing
// Load the audio clip music = getAudio("starWars.au");
// Play the music music.play(); playing = true;
// Record the current time int tempTime1 = (int) System.currentTimeMillis() / 1000;</p><p>while (playing) {</p><p>if ((int) System.currentTimeMillis() / 1000 - tempTime1 >= (THRESHOLD_DELAY + THRESHOLD_PLAY)) {
// Stop the music after 10 seconds, for a total of 14 music.stop(); </p><p>playing = false; </p><p>}</p><p> }</p><p> }</p><p>public void onMouseClick(Location point) {</p><p>// Restart the code <br>this.begin();</p><p>} </p><p>}</p>

Step 4: Sound Sensors

Code Implementation:

The function findSoundMax(int t, int inc) is used for the sound sensor. When implementing the sound sensor, we found that the sensor is too sensitive. When music was on, the sensor would have drastically different values for when the music was loud or soft. As a result, we had to find the maximum sound level in a certain length of time, and use that to tell if music was playing. The function findSoundMax has to integer variables, soundMax and sensorSound. The function makes the sensor listen to the music, then delay for a certain amount of time, t. Then it listens to the music again, and if it is louder this time than before, the louder value is stored as soundMax. It does this inc amount of times. For example, we used t = 50 ms and inc = 20. This means that the sensor repeats the above process 20 times, delaying 50 ms between each listen. The maximum sensor value is then passed into the variable sound.

If sound larger than soundThresh, then we change the value of an integer, x, from -1 to 0. soundThresh is a user-defined value that is experimentally found. Sound levels above this value means music is playing. Below this value is just ambient noise. By setting x=0, we know we no longer need to listen to music: the function findSoundMax is only run when x<0. The code can now continue on to line tracking, collision avoidance, and more.



Step 5: Collision Avoidance

Our groups tested collision avoidance using two different methods: infrared and ultrasonic. Our ultrasonic part was the HC-SR04, and the infrared part was the same as our line trackers.

For our Infrared line trackers, we simply read the value from the line tracker using an analog input, check whether it is above a certain threshold, and if it is, then the object is too close, and the function returns true. If the analog input from the IR sensor is below the threshold, then the function returns false.

Our ultrasonic sensors were more complicated, since they involve sending a pulse and then waiting for it to return, but thankfully Arduino provides example code for the functionality we wanted, under Examples, Sensors, and Ping. This code uses one digital output pin to send a pulse, switches the output pin to input, and then measures the time until that digital input pin registers the sound again. The measured distance is then converted to inches. We changed the example code slightly to return the inches value instead of print it, so we could use it for logic. We also used separate pins for sending the pulse and registering when it returns, because the HC-SR04 piece has separate wires for the input and output trigger signals.

As the infrared sensor is easier to implement than the ultrasonic sensor, we chose the infrared sensor for this specific car, but other members used the ultrasonic sensor for variety.

Step 6: Final Code

The attached code works for

  • Infrared sensor
  • 3 SparkFun line followers
  • Sound sensor
  • 4 motors

And has functionality for

  • Detecting music (loud noises)
  • Line tracking for 14 seconds
  • Avoiding collisions with other cars
  • Staying within the playing field (bouncing off the reflective tape while inside the track)
  • Finding a "chair" (black spot)

See the comments in the code for more explanation.