Techfest 2015 – IIT Bombay

Techfest 2015!

IIT Bombay’s most awaited techfest was held last month from 26th to 28th December.

I participated in Maze Runner, a competition which was part of an event called Technovoltz.

The participants had to build an autonomous robot which could follow a white line and keep track of directions while traversing the maze. The bot had to analyse the path in the dry run. In the final run, it then had to take the correct path through the maze in minimum possible time.

The maze!

Main components of the robot:

After a lot of preparation, I entered the double doors of the Girish Gaitonde Lecture Hall Complex

At the entrance to the lecture hall complex, I was assigned the first slot.

Inside lecture room 002 (for that was the venue), it was completely dark. The maze was made from white vinyl strips pasted on a large wooden board, which was painted black.

The maze also had certain checkpoints, each of which when crossed, added 25 points to the total score.

At the end of the track was a white thermocol block (polystyrene) which on sensing, the maze solver had to blink a red LED to get 5 points.

When my turn came, I calibrated my robot’s sensors (in the fashion that all Pololu sensors are calibrated), set it into Mode 1 (maze analysis mode) and placed it at the start point.

(Note: Mode 2 is for the final run, in which the robot processes the path recorded in the dry run, eliminates all the bad turns and traverses the shortest path from start to end.)

Each participant is given three chances to restart.

The first time, it took an about turn right at the beginning and veered off the track. (Recalibration…)

The second time it went 2 inches forward before going completely cuckoo. (Recalibration again…)

The third time, thankfully, it went ahead and started the run.

All went well on the first run. Yippee!

The only problem was that it took a double turn at a dead-end. This mean’t that I would have to leave it in mode 1 again for the second run. If I put it in mode 2 now, it would get confused while processing the double turn and refuse to move.

So leaving it in mode 1, I took it back to the start point for the final run.

And right there, I made the mistake of turning it off and on again.

When a robot is turned off and on, the sensor calibration has to be done ALL OVER AGAIN.

I re-calibrated it, but something must have gone wonky because it got stuck in a loop and refused to proceed.

In the end, I scored enough points for a participation certificate. (Minimum points required: 60)

A very important point to note is that during the final testing at home (on a regular flex sheet) the maze solver solved the maze five out of five times.

IMG_20151226_073946124

This was quite an achievement and a great learning experience.

Lessons learn’t:

  • The material of the track adversely affects the functioning of a maze solver’s sensors and caster wheel.
  • Ensure that variables for turning are appropriate for any texture and that motors & wheels are also powerful enough.

 

For all you geeks out there who are into programming, here’s the code. Feel free to remix and use.

#include <QTRSensors.h>
// Code written by Raunak Hede  – www.raunakhede.com
#define Kp 1 // experiment to determine this, start by something small that just makes your bot follow the line at a slow speed
#define Kd 15 // experiment to determine this, slowly increase the speeds and adjust this value. ( Note: Kp < Kd)
#define rightMaxSpeed 250 // max speed of the robot
#define leftMaxSpeed 250 // max speed of the robot
#define rightBaseSpeed 100 // this is the speed at which the motors should spin when the robot is perfectly on the line
#define leftBaseSpeed 100 // this is the speed at which the motors should spin when the robot is perfectly on the line
#define NUM_SENSORS 8 // number of sensors used
#define TIMEOUT 2500 // waits for 2500 us for sensor outputs to go low
#define EMITTER_PIN 12 // emitter is controlled by digital pin 2
#define rightMotor1 4
#define rightMotor2 11
#define rightMotorPWM 5
#define leftMotor1 3
#define leftMotor2 6
#define leftMotorPWM 10
#define switchpwr 2 //mode input taken from D9
int leftMotorSpeed = 50;// do not change back to/exceed 100
int rightMotorSpeed = 50;
int turn = 100;
QTRSensorsRC qtrrc((unsigned char[]) {14, 15, 16, 17, 18, 19, 7, 8}, NUM_SENSORS, TIMEOUT, EMITTER_PIN);//sensor connected
unsigned int sensorValues[NUM_SENSORS];
void setup()
{
pinMode(9, INPUT_PULLUP);
pinMode(switchpwr, OUTPUT);
pinMode(rightMotor1, OUTPUT);
pinMode(rightMotor2, OUTPUT);
pinMode(rightMotorPWM, OUTPUT);
pinMode(leftMotor1, OUTPUT);
pinMode(leftMotor2, OUTPUT);
pinMode(leftMotorPWM, OUTPUT);
#define rup digitalWrite(rightMotor1, HIGH);digitalWrite(rightMotor2, LOW);
#define lup digitalWrite(leftMotor1, HIGH);digitalWrite(leftMotor2, LOW);
#define rdown digitalWrite(rightMotor1, LOW);digitalWrite(rightMotor2, HIGH);
#define ldown digitalWrite(leftMotor1, LOW);digitalWrite(leftMotor2, HIGH);
#define f lup;analogWrite(leftMotorPWM, leftMotorSpeed); rup;analogWrite(rightMotorPWM, rightMotorSpeed);
#define l ldown;analogWrite(leftMotorPWM, turn); rup;analogWrite(rightMotorPWM, turn);
#define r lup;analogWrite(leftMotorPWM, turn); rdown;analogWrite(rightMotorPWM, turn);
#define b ldown;analogWrite(leftMotorPWM, 80); rdown;analogWrite(rightMotorPWM, 80);
#define s analogWrite(leftMotorPWM, 0); analogWrite(rightMotorPWM, 0);
#define turnleft s;delay(50); l;delay(240); s;delay(300);
#define turnright s;delay(50); r;delay(290); s;delay(300);
#define hardturnleft s;delay(50); l;delay(1000); s;delay(300);
#define hardturnright s;delay(50); r;delay(1000); s;delay(300);
#define turnaround s;delay(50); l;delay(500); s;delay(300);
#define skip f;delay(200);
#define back b;delay(30);
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
pinMode(12, OUTPUT);
digitalWrite(12, HIGH);
for (int i = 0; i < 200; i++) // make the calibration take about 10 seconds
{
qtrrc.calibrate(); // reads all sensors 10 times at 2500 us per read (i.e. ~25 ms per call)
}
digitalWrite(13, LOW);// turn off Arduino’s LED to indicate we are through with calibration
//print the calibration minimum values measured when emitters were on
Serial.begin(9600);
for (int i = 0; i < NUM_SENSORS; i++)
{
Serial.print(qtrrc.calibratedMinimumOn[i]);
Serial.print(‘ ‘);
}
Serial.println();
// print the calibration maximum values measured when emitters were on
for (int i = 0; i < NUM_SENSORS; i++)
{
Serial.print(qtrrc.calibratedMaximumOn[i]);
Serial.print(‘ ‘);
}
Serial.println();
Serial.println();
delay(500);
}
int lastError = 0;
char dir;
char directions[20];
char newdirections[20];
int i=-1;
void loop()
{
digitalWrite(switchpwr, HIGH);
int mode = digitalRead(9);
if (mode != 0)
{
unsigned int position = qtrrc.readLine(sensorValues);
if ((sensorValues[7] > 900 && sensorValues[6] > 900 && sensorValues[5] < 900 && sensorValues[4] < 900 && sensorValues[3] < 900 && sensorValues[2] < 900 && sensorValues[1] < 900 && sensorValues[0] < 900) || (sensorValues[7] > 900 && sensorValues[6] > 900 && sensorValues[5] > 900 && sensorValues[4] < 900 && sensorValues[3] < 900 && sensorValues[2] < 900 && sensorValues[1] < 900 && sensorValues[0] < 900))
{//right
s;delay(100);
unsigned int position = qtrrc.readLine(sensorValues);//Check again
if (sensorValues[7] > 900 && sensorValues[6] > 900 && sensorValues[5] > 900 && sensorValues[4] > 900 && sensorValues[3] > 900 && sensorValues[2] > 900 && sensorValues[1] > 900 && sensorValues[0] > 900)//dead-end
{
dir = ‘R’;
back;
turnright;
i++;
directions[i] = dir;
}
else
{
dir = ‘F’;
skip;
i++;
directions[i] = dir;
}
}
else if ((sensorValues[7] < 900 && sensorValues[6] < 900 && sensorValues[5] < 900 && sensorValues[4] < 900 && sensorValues[3] < 900 && sensorValues[2] < 900 && sensorValues[1] > 900 && sensorValues[0] > 900) || (sensorValues[7] < 900 && sensorValues[6] < 900 && sensorValues[5] < 900 && sensorValues[4] < 900 && sensorValues[3] < 900 && sensorValues[2] > 900 && sensorValues[1] > 900 && sensorValues[0] > 900))
{//left
dir = ‘L’;
turnleft;
i++;
directions[i] = dir;
}
else if (sensorValues[7] < 900 && sensorValues[6] < 900 && sensorValues[5] < 900 && sensorValues[4] < 900 && sensorValues[3] < 900 && sensorValues[2] < 900 && sensorValues[1] < 900 && sensorValues[0] < 900)//junction
{
dir = ‘L’;
turnleft;
i++;
directions[i] = dir;
}
else if (sensorValues[7] > 900 && sensorValues[6] > 900 && sensorValues[5] > 900 && sensorValues[4] > 900 && sensorValues[3] > 900 && sensorValues[2] > 900 && sensorValues[1] > 900 && sensorValues[0] > 900)//dead-end
{
dir = ‘B’;
turnaround;
i++;
directions[i] = dir;
}
else
{
unsigned int sensors[8];
int position = qtrrc.readLine(sensors);//get calibrated readings along with the line position
int error = 3500-position;
int motorSpeed = Kp * error + Kd * (error – lastError);
lastError = error;
int rightMotorSpeed = rightBaseSpeed + motorSpeed;
int leftMotorSpeed = leftBaseSpeed – motorSpeed;
if (rightMotorSpeed > rightMaxSpeed ) rightMotorSpeed = rightMaxSpeed; // prevent the motor from going beyond max speed
if (leftMotorSpeed > leftMaxSpeed ) leftMotorSpeed = leftMaxSpeed; // prevent the motor from going beyond max speed
if (rightMotorSpeed < 0) rightMotorSpeed = 0; // keep the motor speed positive
if (leftMotorSpeed < 0) leftMotorSpeed = 0; // keep the motor speed positive
//move forward with appropriate speeds
digitalWrite(rightMotor1, HIGH);
digitalWrite(rightMotor2, LOW);
analogWrite(rightMotorPWM, rightMotorSpeed);
digitalWrite(leftMotor1, HIGH);
digitalWrite(leftMotor2, LOW);
analogWrite(leftMotorPWM, leftMotorSpeed);
}
}
else if (mode == 0)
{
s;
recheck:
for(int x=0; x<=sizeof(directions); x++)
{
if (directions[x] == ‘B’)//if there are B signals, go ahead with reprocessing.
{
if (directions[x-1]==’R’ && directions[x+1]==’R’)
{
directions[x-1]=0;
directions[x]=’F’;
directions[x+1]=0;
}
else if (directions[x-1]==’L’ && directions[x+1]==’L’)
{
directions[x-1]=0;
directions[x]=’F’;
directions[x+1]=0;
}
else if (directions[x-1]==’F’ && directions[x+1]==’F’)
{
directions[x-1]=0;
directions[x]=’B’;
directions[x+1]=0;
}
else if (directions[x-1]==’F’ && directions[x+1]==’L’)
{
directions[x-1]=0;
directions[x]=’R’;
directions[x+1]=0;
}
else if (directions[x-1]==’R’ && directions[x+1]==’L’)
{
directions[x-1]=0;
directions[x]=’B’;
directions[x+1]=0;
}
else if (directions[x-1]==’L’ && directions[x+1]==’F’)
{
directions[x-1]=0;
directions[x]=’R’;
directions[x+1]=0;
}
else if (directions[x-1]==’L’ && directions[x+1]==’R’)
{
directions[x-1]=0;
directions[x]=’B’;
directions[x+1]=0;
}
}
}
Serial.println();
//put the processed data into the same array (with no null characters)
int d = -1;
for (int a=0; a<=sizeof(directions); a++)
{
if (directions[a] != ‘\0’)
{
d++;
directions[d] = directions[a];
}
}
Serial.println();//check for any leftover B signals
for (int z=0; z<=sizeof(directions); z++)
{
if (directions[z] == ‘B’)
{
goto recheck;
}
}
for (int z=0; z<=sizeof(directions); z++)//Now print the final data from the new array
{
Serial.print(directions[z]);
}
Serial.end();
// Start final run with processed data
s; delay(6000);
int n = 0;
while(1)
{Serial.println(“Starting final run”);
unsigned int position = qtrrc.readLine(sensorValues);
if ((sensorValues[7] > 900 && sensorValues[6] > 900 && sensorValues[5] < 900 && sensorValues[4] < 900 && sensorValues[3] < 900 && sensorValues[2] < 900 && sensorValues[1] < 900 && sensorValues[0] < 900) || (sensorValues[7] > 900 && sensorValues[6] > 900 && sensorValues[5] > 900 && sensorValues[4] < 900 && sensorValues[3] < 900 && sensorValues[2] < 900 && sensorValues[1] < 900 && sensorValues[0] < 900))
{
if (directions[n] == ‘R’)
{
turnright;
n++;
}
else if (directions[n] == ‘F’)
{
skip;
n++;
}
}
else if ((sensorValues[7] < 900 && sensorValues[6] < 900 && sensorValues[5] < 900 && sensorValues[4] < 900 && sensorValues[3] < 900 && sensorValues[2] < 900 && sensorValues[1] > 900 && sensorValues[0] > 900) || (sensorValues[7] < 900 && sensorValues[6] < 900 && sensorValues[5] < 900 && sensorValues[4] < 900 && sensorValues[3] < 900 && sensorValues[2] > 900 && sensorValues[1] > 900 && sensorValues[0] > 900))
{
if (directions[n] == ‘L’)
{
turnleft;
n++;
}
else if (directions[n] == ‘F’)
{
skip;
n++;
}
}
else if (sensorValues[7] < 900 && sensorValues[6] < 900 && sensorValues[5] < 900 && sensorValues[4] < 900 && sensorValues[3] < 900 && sensorValues[2] < 900 && sensorValues[1] < 900 && sensorValues[0] < 900)//junction
{
if (directions[n] == ‘L’)
{
turnleft;
n++;
}
else if (directions[n] == ‘F’)
{
skip;
n++;
}
else if (directions[n] == ‘R’)
{
turnright;
n++;
}
}
else
{
unsigned int sensors[8];
int position = qtrrc.readLine(sensors);//get calibrated readings along with the line position
int error = 3500-position;
int motorSpeed = Kp * error + Kd * (error – lastError);
lastError = error;
int rightMotorSpeed = rightBaseSpeed + motorSpeed;
int leftMotorSpeed = leftBaseSpeed – motorSpeed;
if (rightMotorSpeed > rightMaxSpeed ) rightMotorSpeed = rightMaxSpeed; // prevent the motor from going beyond max speed
if (leftMotorSpeed > leftMaxSpeed ) leftMotorSpeed = leftMaxSpeed; // prevent the motor from going beyond max speed
if (rightMotorSpeed < 0) rightMotorSpeed = 0; // keep the motor speed positive
if (leftMotorSpeed < 0) leftMotorSpeed = 0; // keep the motor speed positive
//move forward with appropriate speeds
digitalWrite(rightMotor1, HIGH);
digitalWrite(rightMotor2, LOW);
analogWrite(rightMotorPWM, rightMotorSpeed);
digitalWrite(leftMotor1, HIGH);
digitalWrite(leftMotor2, LOW);
analogWrite(leftMotorPWM, leftMotorSpeed);
}
}
}
}

2 comments

Leave a Reply