Getting Started In A World of Robotics

Getting Started In A World of Robotics is a presentation which I have given on multiple occasions as a speaker for Project GEIT (Goans Empowered with Information Technology). Its purpose is to introduce students to the basics of hobby robotics and to inculcate a ‘how-stuff-works’ attitude towards new technology in as simple a manner as possible. Students can also learn how to build a simple robot of their own using the concepts shown in the presentation.

Getting started in a world of Robotics

Rexplorer v2

Rexplorer v2

Rexplorer v2 is a fully autonomous self-mapping robot to be used for indoor purposes.

My original intention was to develop a robot which could map an unknown area and relay the data to a monitoring system so as to provide real-time feedback about the layout of external environment.

I ended up making a robot that maps its own path, generally sticks to moving along the periphery of a room and sends a rough sketch of its traversed path to a smartphone via bluetooth.

This robot is part of the Rexplorer Project and is only an experimental prototype. There are certain conditions for sensing which have not yet been included, due to which undesirable movement may be caused. (Bug-fixes for the same will feature in the next version along with improved sensing algorithms and ultrasonic sensors.)

How it works:

There are 3 infrared proximity sensors at the front and sides of the robot which detect obstructions in its path. These digital signals are sent to an AVR micro-controller (ATMEGA 328 on Arduino UNO) which decides in which direction the robot should turn. The decision then activates the respective motors by sending a set of signals to the motor driver. Simultaneously, a second signal is sent to an Android application on a smartphone, via Bluetooth, containing information about the robot’s current movement which is in turn, used to draw a sketch of its path as it moves in real-time.

The Android application was made using MIT App Inventor 2 and the robot’s program was coded in the Arduino IDE (Integrated Development Environment), based on C++.

List of components: (all components are available at online stores such as robokits.co.in)

  • Wheels – 4 nos.
  • DC Geared motors – 4 nos.
  • Arduino UNO – 1 no. (Any version of Arduino can be used with the given code, provided it has the same or greater number of I/O pins and relevant changes are made in the uploading procedure. Additionally, any development board can be used provided the code’s logic remains the same and sufficient I/O pins are available.)
  • HC-05 bluetooth module – 1 no.
  • Infrared proximity sensors – 3 nos.
  • L298N motor driver – 1 no.
  • Lithium-ion rechargeable battery – 1 no.
  • Jumper wires – lots!

And finally, the codes! As always, please feel free to utilise, remix and improvise upon the codes. (And let me know how it went in the comments below!)

Smartphone application –

Arduino code –

int l1 = 6;
int l2 = 5;
int r1 = 11;
int r2 = 9;

int rs = 100;
int ls = 100;
int rts = 130;
int lts = 130;
//Coded by Raunak Hede-http://raunakhede.com
//drive system
#define f analogWrite(l1, ls); analogWrite(l2, 0); analogWrite(r1, rs); analogWrite(r2, 0);
#define b analogWrite(l1, 0); analogWrite(l2, ls); analogWrite(r1, 0); analogWrite(r2, rs);
#define l analogWrite(l1, 0); analogWrite(l2, lts); analogWrite(r1, rts); analogWrite(r2, 0);
#define r analogWrite(l1, lts); analogWrite(l2, 0); analogWrite(r1, 0); analogWrite(r2, rts);
#define s analogWrite(l1, 0); analogWrite(l2, 0); analogWrite(r1, 0); analogWrite(r2, 0);
#define d delay(200);

//individual hemisphere control
#define leftfor analogWrite(l1, lts); analogWrite(l2, 0);
#define rightfor analogWrite(r1, rts); analogWrite(r2, 0);

#define leftstop analogWrite(l1, 0); analogWrite(l2, 0);
#define rightstop analogWrite(r1, 0); analogWrite(r2, 0);

#define leftback analogWrite(l1, 0); analogWrite(l2, lts);
#define rightback analogWrite(r1, 0); analogWrite(r2, rts);

//MAPPING system
#define forward Serial.write("1");
#define backward Serial.write("4");
#define left Serial.write("3");
#define right Serial.write("2");
#define forright Serial.write("1");Serial.write("2");
#define backright Serial.write("1");Serial.write("2");
#define forleft Serial.write("4");Serial.write("3");
#define backleft Serial.write("4");Serial.write("3");
#define stp Serial.write("0");
int state;
int s1,s2,s3;
void setup()
{
pinMode(l1, OUTPUT);
pinMode(l2, OUTPUT);
pinMode(r1, OUTPUT);
pinMode(r2, OUTPUT);
pinMode(A0, INPUT);
pinMode(A2, INPUT);
pinMode(A3, INPUT);
Serial.begin(9600); //initialize serial communication at 9600 bits per second
pinMode(13,OUTPUT);digitalWrite(13,LOW);
}

void loop()
{
 if(Serial.available()>0)
 {
 int fse=digitalRead(A0);//front
 int lse=digitalRead(A2);//digital
 int rse=digitalRead(A3);//digital
//specify sensor limits
 int fsl=0;
 int lsl=0;
 int rsl=0;
//sets to 1 if closed and to 0 if open
 if(lse==lsl){s1=1;}else{s1=0;}
 if(fse==fsl){s2=1;}else{s2=0;}
 if(rse==rsl){s3=1;}else{s3=0;}

 if(s1==0 && s2==0 && s3==0)
 {//no blocks
 forward;
 f;delay(100);
 }
 else if(s1==1 && s2==0 && s3==1)
 {//sides blocked
 forward;
 f;delay(100);
 }
 else if(s1==1 && s2==1 && s3==1)
 {//all blocked- to rev- add about turn
 stp;
 s;
 }
 else if(s1==1 && s2==1 && s3==0)
 {//turn 90 right
 left;
 r;delay(400);
 }
 else if(s1==0 && s2==1 && s3==1)
 {//turn 90 left
 left;
 l;delay(400);
 }
 else if(s1==0 && s2==0 && s3==1)
 {//wall on right
 forward;
 rightfor;leftstop;
 }
 else if(s1==1 && s2==0 && s3==0)
 {//wall on left
 forward;
 leftfor;rightstop;
 }
 //T-junctions
 else if(s1==0 && s2==1 && s3==0)
 {// front block- turn 90 right
 right;
 r;delay(400);
 }
 }
 else{s;}
}
at school

Rexplorer v2 @ Sharada Mandir School Science Fair 2017

Rexplorer v1 – A robot programmed in Scratch GPIO

Rexplorer v1 – A robot programmed in Scratch GPIO

For the first time, I’ve built a fully functional robot with my trusty Raspberry Pi 2. My last attempt at connecting a motor driver to a Pi resulted in a burnt pi; but that was because I connected its 5v output to the driver’s 5v output pin (recipe for disaster).

Rexplorer is the successful result of research preceded by a burnt Raspberry Pi Mod B and an L298N motor driver which blew a fuse.

By the end of this tutorial you will have a fully functional obstacle detecting robot (provided you follow the instructions carefully).

Disclaimer: The author of this tutorial will not be held responsible for any burnt Raspberry Pi(e)s or indirect damage caused to the same due to negligence (as was the case with the author’s).

As you may already know, the Raspberry Pi is a Linux OS computer.

So first, lets take a quick look at the bot (when unplugged from the monitor/screen, keyboard, mouse and any other peripherals).

HARDWARE

  • Raspberry Pi – Model B 2 or any 40-pin Pi; you can also use Model B, A+, B+ or Zero if you know their respective pinouts
  • Raspberry Pie – Optional, unless you’re hungry
  • Motor Driver – Preferably based on L298N
  • BO motors – 2 nos.
  • Wheels for BO motors – 2 nos.
  • Castor wheel  – 1 BIG wheel
  • Mechanix/Mechano built chassis – You can use any chassis for provided there is space for motors and sensors
  • Jumper wires – As many as you can find
  • A power bank – Only to power the Raspberry Pi and can be substituted with any decent 5v power supply
  • Lithium ion 12v battery pack – To power up the motors.
  • Toggle switch – Optional, as it will be used for the power supply to the motor driver

The mouse, keyboard, monitor/screen and other peripherals which are connected to the Pi when it is not running headless (without a display), will now be referred to as the ‘station’.

The HDMI cable connecting the Pi’s display output should be at least one metre long.

The software of PiBot is done in a modified  version of the programming language (interface actually) called Scratch. The modified version which we will be using is called Scratch GPIO (version 7).

Scratch GPIO is modelled on Scratch v1.4, but in addition to all the other features, it also gives a user direct access to all of the Pi’s GPIO pins. This makes it easy to program the Pi as a robot with motors, sensors and various other hardware peripherals.

Connect all the hardware as shown in the schematic…

pibot_schematic

Or as explained here in words…

The motor driver’s 2 enable and 4 input pins are connected to pins 31, 32, 35, 36, 37, 38 of the Pi respectively; the motors are directly connected to the driver’s output terminals; the driver’s power supply is connected to the 12v battery (directly or with a toggle switch in between) and the GND/negative wires is also connected to the Pi’s GND (pin 40); the proximity sensor’s VCC is connected to the 3.3v output at pin 1 of the Pi, GND at pin 6, and O/P (output) at pin 7.

Between the two, I think you’ll prefer the schematic 😜

SOFTWARE

Boot the Pi to install Scratch GPIO with an internet connection.

Open the LXterminal and type:

wget http://bit.ly/1wxrqdp -O isgh7.sh

After the installer has been downloaded, type:

sudo bash isgh7.sh

Now that Scratch GPIO 7 and its accessory files are installed, let’s get coding!

Open Scratch GPIO7 (you’ll see a shortcut on the desktop) and drag the following blocks into the blank grey area:

pibot_code2

pibot_code3

The ‘broadcast’ blocks normally send messages which act as signals in the programme, but in this case they’re actually changing the state of the GPIO pins. The syntax for any output through broadcast is as follows:

pin<pin number><state>

Where ‘pin number’ is the GPIO pin number as per the pinout numbering and ‘state’ is the output at that pin i.e. either high or low.

Test it by clicking on the arrow keys on your Pi’s keyboard and make sure that the pin numbers are correct.

Right now, the robot should move forward, backward, turn left or right depending on the arrow key pressed. This is a quick and easy way to test your motor driver connections and make sure the wires connect the right pins.

To make it ‘smart’ we need to throw in another script for, let’s say, obstacle detection.

Open the background’s script area by double clicking on its icon near the list of sprites.

Now drag these blocks into the grey area:

pibot_code1

Save the project and close ScratchGPIO7.

Lastly, open an LXterminal window and type:

sudo raspi-config

A configuration list should open. Choose option 3 i.e. Enable boot to Desktop/Scratch and at the next list, choose Desktop log in as user ‘pi’ at the Graphical Desktop.

Now reboot your Raspberry Pi and watch the magic unfold!

As soon as the desktop loads, open ScratchGPIO7, open your project (if it isn’t already open) and hit ‘Enter’. The green flag script(s) should start automatically. The motors will now be activated so please check if the Pi is connected and accordingly hold on to it to prevent any untoward incidents.

The Pi can also be accessed wirelessly over SSH (Secure Shell) and VNC (Virtual Network Computing), so you could consider installing RealVNC on the Pi and a laptop/PC to control it (the robot) remotely.

The robot should (as every good obstacle detector does) stop when it detects an obstacle and continue moving otherwise.

KUKA Robotics Training Programme

KUKA Robotics Training Programme

Last week, I attended a training programme at KUKA Robotics Pune from the 2nd to 4th of May.

During the programme I learn’t how to jog and master the axes, calibrate the various co-ordinate systems and tools, calibrate it for different payloads and supplementary loads and also some basic logic programming.

The trip to KUKA was a bit long as the first day of the training programme coincided with the day of our return from a very long vacation. We took a flight from Amsterdam to Dubai, Dubai to Bombay and Bombay to Goa (with stop-overs) and reached home at 10:30 in the night. The very same night (at around 1:00 a.m.) we left for Pune by road. On reaching Pune at 9:30 the next morning, we drove to the KUKA Robotics Training Centre where the session had already begun. I was an hour late (and jet lagged) but soon caught up with what was being done. There were also three other gentlemen in the training programme who were from CSIR-National Aerospace Laboratories, Bangalore.

Day 1:

Introduction to jogging the 6 axes of a KR16-2 KUKA robotic arm. The robotic arm is controlled using keys or a type of joystick from a handheld device called a smartPAD while jogging. There are 4 operating modes of the robot, namely T1, T2, Auto and Auto-External. Of these 4 modes, T1 allows enabling of motion from the smartPAD with a velocity limit of 25 cm/s. T2 does not have a velocity restriction, (so the safety door of the work area must be kept closed and nobody should be present inside) but programmes running in this mode also require motion to be enabled from the smartPAD. Auto mode allows the program to run without human intervention. Auto-External requires an external PLC to be connected, usually because inputs may be required from the operator in that particular program, but otherwise runs autonomously. I experimented with a gripper attachment on the robotic arm and learn’t how to master each of the robot’s axes with an EMD (Electronic Mastering Device).

Day 2:

Calibration of the robot for carrying a payload, supplementary load and tool. I learnt to calibrate the Tool and Base Co-ordinate Systems and also some basic programming for Point-to-point motion (PTP/Axis specific movement), Linear & Circular motion (Controlled Path movement). In addition to these, I also learn’t to archive and restore files in the smartPAD.

Day 3:

Usage of continuous motion and SPLINE movement and change of orientation for the same position (x,y,z) in PTP motion. Collision detection through changes in torque and synchronised output motions were also covered along with logic programming. There are 5 basic concepts in logic programming: inputs, outputs, timers, time dependant ‘wait’ functions and signal dependant ‘wait’ functions. Outputs can further be subdivided into simple outputs, pulse outputs and motion synchronised outputs.

These 3 days have been an invaluable learning experience.

Sincere thanks to Mr. Saurabh Gupte, Mr. Ravi Teja and KUKA Robotics for permitting me to attend the training programme.

KUKA training programme_group photo

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);
}
}
}
}
Quark 2015 – Birla Institute of Technology & Science (BITS) Goa, Vasco

Quark 2015 – Birla Institute of Technology & Science (BITS) Goa, Vasco

Quark 2015!

This is one of India’s largest tech fest, which took place recently at the BITS Pilani, Goa campus in Vasco.

The festival was from 6th to 8th of February and had some great minds from across the world attending it.

I was there too. Participating in Line Following, Robot Race and for the first time, Robokick!

20150114_165503  _DSC0771  IMG_0049

Line Following:

Objective: Design and build a fully autonomous robot which can traverse a black line on a white background.

Arena: Track had normal curves, right angles, sharp acute-angle turns, T-junctions, X-junctions, Y- junctions, Inverted Y- junctions and loops.

Line Follower performance: LFR v2.0 was smoooooth, thanks to the PWM control. (Pulse Width Modulation) It traversed all the angles well (90, 60 & 120 degree). Even the T- junctions were quite good apart from the fact that recovery took time. The only problem occurred at the inverted Y- junctions. Due to multiple case clashes (a common error faced by maze solving line followers), the bot took the first path that it sensed. i.e. the pathway back into the loop! Oh nooooo! And there it would continue traversing the loop until I picked it up and put it back on the correct path. (with a hefty penalty of course!)

Main Components:

  • Arduino UNO, rev 3 (ATMEGA 328)
  • L298 motor driver
  • 12v, 1A, Li-ion rechargeable battery
  • RKI-1032 digital line sensor (7 sensor array with TTL output)
  • 320 rpm BO motors

Click on the link to download the C++ code for LFR at Quark 2015.

Quark2015_BITS_Line following

Roborace:

Objective: Design and build a wired/wireless, remote controlled all terrain racer (Basically, a smaller version of an ATV, without you sitting inside it.)

Arena: Track was on a rough terrain which caused a lot of bouncing about. It was a world of obstacles. The track consisted of slopes up to 45 degrees, car tires with loosely stretched plastic to cover the hollow depression, dry grass, sand, a slow windmill, soda-can speed breakers & thermocol obstacles which had to be pushed into fixed areas. Another extremely difficult obstacle, was the double slope platform with a slit in the middle. This consisted of a 45 degree incline upwards, a flat platform with humps of about 1.5 feet and a 45 degree slope downwards. Now while you’re imagining all this, add a 3 inch slit in the middle of the 9 inch wide path. If you’re still having trouble visualising this perilous path, then please watch the video below.

Racer performance: ATR v1.0 performed exceedingly well here. Just a few glitches like hitting the windmill, rumbling off the track once or twice, and being unable to climb the 45 degree incline caused deduction of points. The racer also had weight problems while trying in vain to get out of the sunken plastic in the tire. I think it’s worth mentioning that ATR was one of the few wireless racers on the whole campus.

Main Components:

  • RKI-1014 Rx/Tx module (RF 4-way remote control)
  • DPDT switches
  • Lock n Lock tiffin
  • 12v, 1A, Li-ion rechargeable battery
  • 500 rpm Gear motors
  • Powder coated multi-purpose metal chassis

Quark2015_BITS_Roborace

Robokick:

Objective: Design and build a wired/wireless, remote controlled robot which can play one-on-one football with another robot. It should be able to be a good striker and, at the same time, be able to defend it’s own goal.

Arena: This event was held in a square arena of 3×3 meters. The arena had markings on it just like a real football field. There were two open shoeboxes used as goals. A smiley sponge ball was used in the game.

Robot performance: Frankly speaking, my registration for the Robokick event was a spot entry. Previously I had no intention of participating in Robokick, mostly because I had no clue whether my bot would meet the requirements. (They did mention a shooting mechanism on the website. Something my bot lacked completely.) During the Roborace, an announcement was made stating that participants of Roborace were also eligible for Robokick and that spot entries would be accepted. And so I entered the competition with ATR v1.0! After adding a couple of metal plates near the wheels, the very same robot which jumped off a ramp, was ready to play football!

Main Components:

  • RKI-1014 Rx/Tx module (RF 4-way remote control)
  • DPDT switches
  • Lock n Lock tiffin
  • 12v, 1A, Li-ion rechargeable battery
  • 500 rpm Gear motors
  • Powder coated multi-purpose metal chassis
  • Small metal rectangular plates from various MECHANIX sets (for striking/goalkeeping)

 

Surprisingly, I won the 3rd place at Robokick☺

IMG_20150208_220531223_HDR

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.

Times of India, Goa Edition- 15th November 2014

Times of India, Goa Edition- 15th November 2014

20141115_Times of India Goa Edition_Raunak

Thank you Gauree Malkarnekar & Rajtilak Naik for putting me on Page 1.

Technival 2014 – National Institute of Technology, Goa

Technival 2014 – National Institute of Technology, Goa

Recently, NIT Goa had their techfest, Technival 2014. I participated in two events held there.

The first was Laburinthos (Line following) held on 8th November

Laburinthos

And the second was RUSH, a race for All Terrain Vehicles.

RUSH

LFR v1.0 came 4th for Laburinthos and ATV Bot bagged the 2nd place in RUSH.

Laburinthos was a simple line following competition where speed was of essence. The track was quite large and mostly consisted of straight lines and sudden sharp curves. The biggest challenge was speed and lighting.

LFR v1.0

Towards the end of the track a false trigger caused LFR v1.0 to turn back and hence it took longer to finish the track.

Here’s a video of LFR v1.0 at the line following event:

 

RUSH was a race for which teams had to build an All Terrain Robot which could race on rollers, steep slopes, rubble and sand. There were also potential hazards like rock pendulums. The robot also had to maneuver through narrow spaces between vertical poles, which if touched, would result in a time penalty of 5 seconds. The same penalty was given for touching the walls and the rock pendulums.

ATV Bot at RUSH

Here’s a video of ATV Bot at the event:

Some Photographs of the event.

Photo & Video Credits:  Annette Paul, Sanmitra Naik, Roheet Hede