Introduction: PathFinder

This Instructable explains how to setup a development environment on Windows to create a robot capable of finding his way around a path. The robot is also controlled from the computer, using Bluetooth, from where it receives commands to modify its behavior.

Step 1: Preparing Development Environment

Material Requirements

The presented project requires the following hardware pieces:

  • RedBot Basic Kit: is a platform for teaching basic robotics and sensor integration!

https://learn.sparkfun.com/tutorials/assembly-gui...

  • Bluetooth Bee: is an easy to use Bluetooth Serial Port Profile(SPP) module compatible with existing Xbee sockets, designed for transparent wireless serial connection setup.

http://www.seeedstudio.com/wiki/Bluetooth_Bee

  • White hard-paper and black tape: These are used to create the path the robot will follow. This is shown in the image above.

Step 2: Setting Up Your Development Environment - IDE

This Instructable explains how to setup your development environment in a Windows system. We used Windows 8.1. The software you will need is:

Step 3: Setting Up Your Development Environment - FTDI Drivers

FTDI Drivers: The board used in this examples makes use of the FT232RL which is one of the more commonly used ICs used to convert USB signals to UART signals. This process is very handy in that it allows you communicate with and upload code to an Arduino or other microcontroller without the need for an external programmer. SparkFun carries a board called the FTDI Basic that conveniently breaks out the necessary pins on the FT232RL to perform these actions.

https://learn.sparkfun.com/tutorials/how-to-instal...

See the image above!

Step 4: Setting Up Your Development Environment - RedBot Arduino Library

RedBot Arduino Libraries: Arduino libraries take a complex task and boil it down to simple to use functions. Arduino users have written lots of exciting add-ons for Arduino and there are special libraries to work with RedBot.

https://learn.sparkfun.com/tutorials/getting-start...

See the image above!

Step 5: Prepare Windows

Before you can communicate with your RedBot you need to make some setting changes in your Windows system:

Enable the COM ports for Bluetooth

This step allows you to communicate with the robot using Bluetooth as if you were using the actual serial ports.

NOTE: Make sure you pay attention to what COM you will have incoming or outgoing traffic! Later you will need that information from processing.

The steps to enable COM ports using Bluetooth are:

Step 6: Open the Control Panel. Search for Bluetooth. Click on the “Change Bluetooth Settings” Link.

Step 7: In the Windows That Just Opened, Select the “Options” Tab and Check the “Allow Bluetooth Devices to Find This PC” Option.

Step 8: Select the “COM Ports” Tab. Click on the “Add” Button. Select the “Incoming” Option and Click the “OK” Button. Click Again on the “Add” and Select the “Outgoing” Option and Click the “OK” Button.

Step 9: You Should End-up Seeing Something Like the Image Below With a List of COM Ports Listed. Make Sure You Note Which Port Is Set for Incoming and for Outgoing Since This Will Be Used in the Processing Code.

Click in the “OK” button.

Step 10: Coding

Now, we are ready to start coding. There is on caveat to this. We faced the situation that sometimes our code would not upload or execute. As you can see in the image below, the SparkFun board has to modes to work with the serial port.

In order for our code to upload we had to turn this switch to Software “SW” and for it to run we had to set the switch to Hardware “HW”.

Step 11: Arduino - Code

The following code was edited using Arduino 1.6.7. This is the full listing of the code.

#include
RedBotSensor left = RedBotSensor(A3); // initialize a left sensor object on A3 RedBotSensor center = RedBotSensor(A6); // initialize a center sensor object on A6 RedBotSensor right = RedBotSensor(A7); // initialize a right sensor object on A7

// constants that are used in the code. LINETHRESHOLD is the level to detect // if the sensor is on the line or not. If the sensor value is greater than this // the sensor is above a DARK line. // // SPEED sets the nominal speed

#define LINETHRESHOLD 800 #define SPEED 60 // sets the nominal speed. Set to any number from 0 - 255. #define CORRECTIONFACTOR 10 #define ADJUSTMENTTHRESHOLD 4000 //milliseconds to start an adjustment in advance

RedBotMotors motors; int leftSpeed; // variable used to store the leftMotor speed int rightSpeed; // variable used to store the rightMotor speed unsigned long startTime; int correctionIndex = 0; int correctionCounter=0; unsigned long corrections[20]; int correctionsDir[20]; char action; bool ticket=false;

void setup() { Serial.begin(9600); Serial.println("Welcome to experiment - Line Following"); Serial.println("------------------------------------------"); delay(2000); Serial.println("IR Sensor Readings: "); delay(500); startTime = millis(); corrections[0] = 0; leftSpeed=-SPEED; rightSpeed=SPEED; }

void loop() {

// Serial.print(left.read()); // Serial.print("\t"); // tab character // Serial.print(center.read()); // Serial.print("\t"); // tab character // Serial.print(right.read()); // Serial.println(); // Serial.print("Action: "); // tab character // Serial.print(action); // Serial.println(); if (action == 'g') {

// if all sensors are on black or up in the air, stop the motors. // otherwise, run motors given the control speeds above. if ((left.read() > LINETHRESHOLD) || (center.read() > LINETHRESHOLD) ) { turn(0); } else if ( (center.read() > LINETHRESHOLD) || (right.read() > LINETHRESHOLD) ) { turn(1); } else { applyAdjustment(nextCorrection()); motors.leftMotor(leftSpeed); motors.rightMotor(rightSpeed);

} delay(0); // add a delay to decrease sensitivity. } else { startTime = millis(); motors.brake(); } }

void turn(int direct) { if (correctionCounter>=0)correctionCounter--; int adjust= correctionCounter*500; addCorrection(direct,adjust); motors.stop(); leftSpeed = 200; rightSpeed = -200;

motors.leftMotor(leftSpeed); motors.rightMotor(rightSpeed); delay(100);

if (direct == 0) { leftSpeed = -(SPEED - 50) * 2; } else { rightSpeed = SPEED - 50 * 2; }

motors.leftMotor(leftSpeed); motors.rightMotor(rightSpeed); delay(250);

leftSpeed = -SPEED; rightSpeed = SPEED; }

void addCorrection(int Direction,int correctionTime) { corrections[correctionIndex] = millis() - startTime-correctionTime; correctionsDir[correctionIndex] = Direction; Serial.println("correction"); Serial.println(corrections[correctionIndex]); Serial.println(correctionsDir[correctionIndex]); correctionIndex++; correctionCounter++; }

int nextCorrection() { int i = 0; unsigned long currentTime = millis() - startTime; while ((corrections[i] < currentTime) && (i < correctionIndex)) i++; return i; }

void applyAdjustment( int nextCorrectionIndex) { unsigned long currentTime = millis() - startTime; unsigned long remainingTime = corrections[nextCorrectionIndex] - currentTime; //Time to correct if (remainingTime < ADJUSTMENTTHRESHOLD) { if (correctionsDir[nextCorrectionIndex] == 1) { rightSpeed = SPEED + applyWeight(remainingTime); leftSpeed = -(SPEED - applyWeight(remainingTime)); } else { rightSpeed = SPEED - applyWeight(remainingTime); leftSpeed = -(SPEED + applyWeight(remainingTime)); } ticket=true; } else if((currentTime > corrections[nextCorrectionIndex]) && (ticket==true)) { ticket=false; correctionIndex++; }

else{ //No correction leftSpeed = -SPEED; rightSpeed = SPEED; } }

int applyWeight(int wRemainingTime){ unsigned long currentTime = millis() - startTime; //int remainingTime=(int)abs(correctionsDir[nextCorrectionIndex]-currentTime); int newSpeed =0; if ((wRemainingTime=2000)){ newSpeed=CORRECTIONFACTOR*1; } else if ((wRemainingTime<2000)&(wRemainingTime>=1000)){ newSpeed=CORRECTIONFACTOR*2; } else if ((wRemainingTime<1000)&(wRemainingTime>=400)){ newSpeed=CORRECTIONFACTOR*3; } else if (wRemainingTime<400){ newSpeed=CORRECTIONFACTOR*1; } return newSpeed; }

void serialEvent() { if (Serial.available()) { action = (char)Serial.read(); if (action == 'g') { correctionIndex=0; correctionCounter=0; } Serial.println("EVENTO"); } }

The code in the “setup” method is regular standard code for setting up communication to serial ports and diagnosis information. The “delays” are important so that you give time for all the system to be up and running.

The “loop” code

The loop code is in charge of continuously looking at the value in the sensors. When one of those sensors reaches a predefined threshold the robot should take appropriate actions.

If the left-sensor reaches the tape (threshold), then, the robot must turn to the right. Likewise, if the right-sensor reaches the tape (threshold) , the robot must turn to the left.

The robot uses a knowledge base where it records the time when it crashed against the line. During each run, the robot records each crash and then in the future runs it will search in its knowledge base to "look-ahead" for crashes and corrects its path.

There is also "adjustments". For example, lets say that in the first run the robot crashed at seconds 4 and 9. In the crash at second 4 the robot had to go back a little to correct the path and hence loses some time. That means that the crash at second 9 would happen at a different time in the next runs if the crash at second 4 is avoided. This "avoidance" instance is tracked in the "correctionCounter" variable. The direction of the correction is also tracked.

The "applyWeight" method is used to add a weigth to the correction speed depending on how close we are to the next predicted crash. The closer to the next crash the faster the adjustment must happen.

The “turn” code

This code makes the robot turn to the left or the right according to the arguments passed to it. The actual work in this code is to be able to determine the distance and speed to move around in order to get back on track. This is basically determined by try-and-fail approach.

See how the speed of the motor is initially set to a base of 200 and -200 for the left and right motors respectively. This values in the speed will make the robot to go backwards.

Depending on the direction to turn, the value of the speed is recalculated for one motor or the other. This is the way we make the robot to go back on track.

As simple as this code might look like, this makes the robot to go around any kind of path and when reaching an end, it can find his way around to go back and start the path again.

Step 12: Processing - Code

The code written in processing is fairly simple and is used to start and stop the robot remotely.

As you can see, here you should specify the port that you will use to communicate with the robot. In this case, it is COM6 but for some other people it would be COM5.

So far the code works for starting and stopping the robot.

/**********************************************************************

Estudiantes:

- ErickCarvajal

- Daniel Madriz

- Alexander Garcia

***********************************************************************/

import processing.serial.*;

Serial myPort; // Create object from Serial class

void setup()

{

size(200,200); //make our canvas 200 x 200 pixels big

String portName = Serial.list()[0]; //change the 0 to a 1 or 2 etc. to match your port

myPort = new Serial(this, "COM6", 9600);

}

void keyPressed()

{

println("key pressed = " + key);

if (key == 'g') {

myPort.write('g'); //send a 1

println("g");

}

else if (key == 's') {

myPort.write('s'); //send a 1

println("s");

}

else{

println("Invalid Key");

}

}


Step 13: Uploading the Code to the Robot

In order to upload the code, you need to move the ports switch to software mode as shown in the image 1.

Then connect the RedBot to your computer. You will know if it worked by looking at the ports in the Arduino IDE at “Tools -> Ports”. You will see an additional port listed. In this case, it is COM4 the port used to upload code from the IDE to the board. This is shown by picture 2.

Step 14: Running the Robot

In order for the robot to work, you will need to change the ports switch in the board back to hardware, as shown in the image 1.

The simple turn the power of the board on and run the processing program. Hit the “g” key and the robot will start moving. Often times, the robot will need you to lift it up a little bit. This will reset the sensor values.

Look at the video for a run!!!

Arduino All The Things! Contest

Participated in the
Arduino All The Things! Contest