Quark 2016 – BITS Pilani, K.K. Birla Goa Campus

Quark 2016 – BITS Pilani, K.K. Birla Goa Campus

Quark 2016 – A Cosmic Odyssey

Days of festival: 5th, 6th & 7th February 2016

I participated in Line Following, Roborace and, for the first time, Open Showcase!

RoboRace

Objective: Design & build a remote controlled all-terrain racer that can traverse any given path with obstacles like rocks, sand, slopes, uneven ground, mud, etc.

Dates of competition: 5th & 6th

Venue: Uneven grounds outside B-Dome

Home test report: Excellent traction, thanks to the custom-made wheels (each wheel was actually a pulley with a track belt bound tightly over it) Gains speed very quickly and can even climb out of a small car tyre.

Results:

5th Feb, Round 1 – The bot completed the track without stopping, and clocked a very good timing, however, the high traction wheels turned out to be a massive hindrance while making spot turns. This factor slowed it down, but it made up for that on the straight paths.

The bot qualified for Round 2, which was to be held on Day 2, but unfortunately, due to a last minute shorting onboard the wireless module, the bot was unable to participate.

Quark_2016_RoboRace_participation_certificate

Open Showcase

Objective: Present an innovative idea that solves a problem.

Dates of competition: Day 2

Venue: CC lobby

My Idea (for the EEE category): CUA (Computer Usage Alert) is a plug-n-play USB device that alerts you to get up and stretch at 20 minute intervals. It has an ATtiny85 micro controller with a program that sends a signal to a buzzer to beep every 20 minutes, thereby alerting you to get up. This process continues until it is unplugged or the computer/laptop to which it is plugged is shut down.

The judging criteria was as follows:

  • Innovation
  • Feasibility and Sustainability
  • Cost Effectiveness
  • Social Viability
  • Discipline
  • Project Report

Quark_2016_Open_Showcase_participation_certificate

Line Following

Objective: Design, build & program a line following robot (LFR) which can traverse a black track on a white background with obstacles like acute angle, obtuse angles, right angles, dashed lines, curves and reach the finish line in shortest possible time. The track width will be 2cm to 3cm. (As per the rules mentioned online)

Screen Shot 2016-02-16 at 8.28.51 pm

Dates of competition: 6th & 7th

Venue: C-306

Home test report: Running very well. I’d say that is has an 80% chance of making a new record.

Competition day: “Holy mackerel! The track width is 4cm!“. I asked the organiser about it. He measured the track width and calmly told me that extra calibration time would be given. And as if to put salt on that wound, the track had 4 places where there were curved, dashed lines with acute turns onto more curved lines!

Results:

6th Feb, Trial 1 – The LFR started out well and then went completely cuckoo. Though it has a PID algorithm in it, the LFR seems to be in its own world. (Thanks to the extra centimetre in the width)

6th Feb, Trial 2 – I managed to fix a few turns, but the PID algorithm still seems to be completely inactive.

(Fortunately, everyone had problems running on the first day, so everyone qualified for the next round on day 2. That night, I sat coding till 1:00 A.M. and finally managed to fix it.)

7th Feb, Trial 1 – The new code is working and the PID is perfect, but a few changes still need to be made in the acute turns. Overall, it’s running well.

7th Feb, Trial 2 – This run went very well, except for the fact that it went off the track 5 times (which means that 25 seconds will be added to my total time of 38 seconds, as a penalty)

I finished my turn just after lunchtime, so I had the rest of the day to go around the campus and watch the final rounds of the other competitions.

At around 4 o’clock I received a phone call from the organiser, telling me that I had won the 2nd place.

IMG_20160207_185732

 

For all you geeks out there, here’s my LFR code. Feel free to tweak and reuse:

#include <QTRSensors.h>
//Code written by Raunak Hede
//https://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 180 // max speed of the robot
#define leftMaxSpeed 180 // max speed of the robot
#define rightBaseSpeed 50 // this is the speed at which the motors should spin when the robot is perfectly on the line
#define leftBaseSpeed 50  // 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

int P, D;
int leftMotorSpeed = 50;
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(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, 80); rup;analogWrite(rightMotorPWM, 80);
  #define l ldown;analogWrite(leftMotorPWM, turn);  rup;analogWrite(rightMotorPWM, turn);
  #define r lup;analogWrite(leftMotorPWM, turn);  rdown;analogWrite(rightMotorPWM, turn+50);
  #define b ldown;analogWrite(leftMotorPWM, 80); rdown;analogWrite(rightMotorPWM, 80);
  #define s analogWrite(leftMotorPWM, 0);  analogWrite(rightMotorPWM, 0);

  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
  pinMode(12, OUTPUT);
  digitalWrite(12, HIGH);
  for (int i = 0; i < 500; 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;

void loop()
{
  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)
  {//right
      s;delay(50);  r;delay(300); s;delay(50);
  }
  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)
  {//left
      s;delay(50);  l;delay(300); s;delay(50);
  }
  
  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)
  {//right
      s;delay(50);  r;delay(280); s;delay(50);
  }
  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)
  {//left
      s;delay(50);  l;delay(280); s;delay(50);
  }
  
  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)
  {//acute right
    f;
  }
  
  else
  {//Execute the PID algorithm
    unsigned int sensors[8];
    int position = qtrrc.readLine(sensors);//get calibrated readings along with the line position
    int error = position-3500;
    
    P = Kp * error;
    D = Kd * (error - lastError);
    
    int motorSpeed = P + D;
    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);
  }
}
Techfest 2015 – IIT Bombay

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);
}
}
}
}
LFR “Microcontroler-less!” Mini

LFR “Microcontroler-less!” Mini

Who said robots need a microcontroller to be smart? This robot certainly doesn’t believe that!

Presenting: LFR Mini! A line follower of the non-programmable kind!

LFR Mini

Since LFR Mini has no formal “brain”, it depends almost entirely on the digital line sensor to do the job. However, as you may know, a line sensor works on the principle of reflectance (i.e. dark colours absorb, light colours reflect), and therefore transmits signals based on this logic:

If the colour detected is black

then transmit 0 (negative signal)

If the colour detected is white

then transmit 1 (positive signal)

Hmm… thats good. But only for a white line follower. What if it has to follow a black line?

Fortunately, there is an IC available that can convert signals. e.g. 0 is converted to 1

This IC, popularly known as the NOT Gate, will simply input the negative signal (black) from the sensor and convert it into a positive signal for the motors. Likewise, a positive signal will be converted to a negative signal for the motors.

So far, so good. Just one last challenge to tackle. The 5v signal from the IC, is not enough for the 150 rpm BO motors. The voltage needs to be amplified. So lets throw in a couple of good old NPN transistors. They use 5v from the IC as a trigger and provide an amazing supply of 9v to the motors.

And, just to err on the side of caution, LFR Mini also has a couple of half-wave rectifier diodes to prevent the transistors from back EMF (reverse electromotive force which can cause shorting of parts in a circuit).

Here’s a video of LFR Mini following it’s first line:

The stuff that went into it:

I] The board:

  • 7805 IC, 5v Voltage Regulator (1)
  • 7404 IC, NOT Gate (1)
  • Male header pins (2, for battery)
  • Female header pins (4, Two for each motor)
  • Male to female wires (2, from battery snap to battery pins & 4, from IC input to sensor output)
  • NPN Transistors (2)
  • Half-wave rectifier diodes (2)

II] The rest of the robot:

A top view of the final robot:

LFR Mini-Top View

Credits: Pravin Kakode (krafters.goa@gmail.com) for laser cutting the acrylic chassis.

Line following Robot

Line following Robot

Hello everyone!

This post is all about a line following robot built by my friend and I. We call it “Sataklela robot”, (which means “crazy robot” in Marathi!) because sometimes the silly thing would go round and round chasing it’s tail if the programming was wrong!

This robot can follow almost any black line on a white background. (We used a white flex sheet with an ellipse shaped black color track printed on it)

It also stops dead in its tracks if it senses an obstacle in front of it, thereby protecting itself and the obstacle (especially if the obstacle happens to be your snoozing pet!) from a collision. However, one of the best parts of this robot, is the fire sensor. If the sensor detects a fire in front of the robot , it turns on a mini fan which blows out the fire.

Here’s a peek into what went into this bot:

Stuff that went into it:

1]  Hardware

  • Chassis
  • Wheels (2)
  • Techno board (Inventrom, Goa)
  • Digital line sensor (Robosoft Systems, Mumbai)
  • Proximity sensor (Robosoft Systems, Mumbai)
  • Light Dependent Resistor’s (2)
  • Transistors (2)
  • Potentiometers (2)
  • 9 volt battery
  • Fan blade (small toy plastic type)
  • 12 volt rechargeable lithium-ion battery
  • Nuts and bolts
  • Metal brackets
  • Castor wheel
  • Usbtiny  AVR programmer

2]  Software

  • ICC 7 for AVR
  • Sinaprog (version 1)

Assembly of parts was done as shown in the pictures:

all views of line follower

Labeled Diagram:

labeled diagram of line follower

The programming was done in embedded C, in a software called ICC 7 for AVR. For burning the program onto the ATMEGA 32  micro-controller, Sinaprog version 1 was used.

Click on this link to view the Program.

The entire project took a week to complete. Right from putting the first screw to testing the final product. We were so happy when we saw it run properly without any glitches!

Note: This robot was built for a project competition at Rayeshwar Institute of Technology in Goa where my teammate, Mithila Prabhudesai, and I won the 4th place against 19 other teams consisting of engineering students.

Raunak Hede & Mithila Prabhudesai

This project was featured in an online magazine Young Buzz. Click here to view the article.