Robotics Project

Fall 2004

 

1. Calibration of the Infrared sensors

 

The first task to be accomplished is the calibration of the sensors. Since each sensor demonstrates small deviations from the absolute scale, it has to be experimentally found what values correspond to what distances.

 

Using the programs show below, the following rough tables have been calculated to allow for rough adjustments.

 

Calibrate_IR_GP2D12.osc

oDio1 Y = new oDio1;

oDio1 R = new oDio1;

oDio1 G = new oDio1;

oEvent Go = new oEvent;

oEvent IncrementCenterEvent = new oEvent;

Byte Enabled;

 

oIRRange GP2D12 = new oIRRange;

oSerial Com = new oSerial;

 

Sub void Main(void)

{

      

  Enabled = 0;

 

  GP2D12.IOLine = 2;

  GP2D12.Center = 20;

  GP2D12.Operate = cvTrue;

 

  Y.IOLine = 6;

  Y.Direction = cvInput;

  oWire GoWire = new oWire;

  GoWire.Input.Link(Y);

  GoWire.Output.Link(Go);

  GoWire.Operate = cvTrue;

 

  G.IOLine = 5;

  G.Direction = cvInput;

  oWire IncrementCenterWire = new oWire;

  IncrementCenterWire.Input.Link(G);

  IncrementCenterWire.Output.Link(IncrementCenterEvent);

  IncrementCenterWire.Operate = cvTrue;

 

  Com.Baud = cv9600;

  Com.Operate = cvTrue;

 

  R.IOLine = 7;

  R.Direction = cvOutput;

  R.Value = 1;

      

   while(1)

       {

         Tune_IR(1);

      }

}

 

Sub void Tune_IR(Byte Dummy)

{

 

      if (Enabled == 0) return;

 

       while (Enabled == 1)

       {

              Com.Value = GP2D12.Value;

      }

}

 

 

Sub void Go_Code(void)

{

   Enabled = 1 - Enabled;

}

 

Sub void IncrementCenterEvent_Code(void)

{

       GP2D12.Center = GP2D12.Center + 1;

      Com.Value = 1;

      Com.Value = GP2D12.Center;

}

 

Calibrate_IR_GPD120.osc

oDio1 Y = new oDio1;

oDio1 R = new oDio1;

oDio1 G = new oDio1;

oEvent Go = new oEvent;

oEvent IncrementCenterEvent = new oEvent;

Byte Enabled;

 

oIRRange GP2D120 = new oIRRange;

oSerial Com = new oSerial;

 

Sub void Main(void)

{

      

  Enabled = 0;

 

  GP2D120.IOLine = 1;

  GP2D120.Center = 20;

  GP2D120.Operate = cvTrue;

 

  Y.IOLine = 6;

  Y.Direction = cvInput;

  oWire GoWire = new oWire;

  GoWire.Input.Link(Y);

  GoWire.Output.Link(Go);

  GoWire.Operate = cvTrue;

 

  G.IOLine = 5;

  G.Direction = cvInput;

  oWire IncrementCenterWire = new oWire;

  IncrementCenterWire.Input.Link(G);

  IncrementCenterWire.Output.Link(IncrementCenterEvent);

  IncrementCenterWire.Operate = cvTrue;

 

  Com.Baud = cv9600;

  Com.Operate = cvTrue;

 

  R.IOLine = 7;

  R.Direction = cvOutput;

  R.Value = 1;

      

   while(1)

       {

         Tune_IR(1);

      }

}

 

Sub void Tune_IR(Byte Dummy)

{

 

      if (Enabled == 0) return;

 

       while (Enabled == 1)

       {

              Com.Value = GP2D120.Value;

      }

}

 

 

      

Sub void Go_Code(void)

{

   Enabled = 1 - Enabled;

}

 

Sub void IncrementCenterEvent_Code(void)

{

       GP2D120.Center = GP2D120.Center + 1;

      Com.Value = 1;

      Com.Value = GP2D120.Center;

}

 

 

GD2D12


oIRRange Value

Centimeters

30

5

23

10

25

12

20

15

23

20

31

25

48

30

64

45

78

60

85

75

-128

85

 


GD2D120

oIRRange Value

Centimeters

37

10

58

20

79

25

92

30

104

40

-128

50


 


 

 

 

 

Listing of the computer program that is used to accept the values and to display them on the screen. For clarity only the code pertaining to the logic is listed. The complete file and the rest of the project are available at the download section.

 

// Fill in DCB: 57,600 bps, 8 data bits, no parity, and 1 stop bit.

 

   dcb.BaudRate = CBR_9600;     // set the baud rate

   dcb.ByteSize = 8;             // data size, xmit, and rcv

   dcb.Parity = NOPARITY;        // no parity bit

   dcb.StopBits = ONESTOPBIT;    // one stop bit

 

   fSuccess = SetCommState(hCom, &dcb);

 

   if (!fSuccess)

   {

      // Handle the error.

      printf ("SetCommState failed with error %d.\n", GetLastError());

      return (3);

   }

 

   printf ("Serial port %s successfully reconfigured.\n", pcCommPort);

 

   char inBuffer[512], outBuffer[32], outBuffer1[16], outBuffer2[16];

   int nBytesToRead = 16;

   DWORD nBytesRead, nBytesWritten;

 

   while(1) {

 

          ReadFile(hCom, &inBuffer, nBytesToRead, &nBytesRead, (LPOVERLAPPED)NULL);

          for ( int i = 0; i < nBytesRead; i++ )

                 printf("%d, ", inBuffer[i]);

 

          Sleep(25);

   }

 

 

2. Calibration of the Servos

 

Each Servo is controlled by value between -128 and +127. The speed, however, is not linear, so we have to use a program like the one listed below to determine the optimal speeds for the robot, when going forward, and the differences of speed of the two wheels, for smooth turns.

It is very helpful if the program below is run when the robot is connected to a computer, since we can see the speed output on the screen.

 

oDio1 Y = new oDio1;

oDio1 R = new oDio1;

oDio1 G = new oDio1;

 

oIRRange LeftMeasure = new oIRRange;

oIRRange RightMeasure = new oIRRange;

oServoX LeftServo  = new oServoX;

oServoX RightServo = new oServoX;

oSerial com = new oSerial;

 

oEvent Increase = new oEvent;

oEvent Decrease = new oEvent;

 

Sub void Main(void)

{

  Y.IOLine = 6;

  Y.Direction = cvInput;

  oWire increaseSpeed = new oWire;

  increaseSpeed.Input.Link(Y);

  increaseSpeed.Output.Link(Increase);

  increaseSpeed.Operate = cvTrue;

      

  G.IOLine = 5;

  G.Direction = cvInput;

  oWire decreaseSpeed = new oWire;

  decreaseSpeed.Input.Link(G);

  decreaseSpeed.Output.Link(Decrease);

  decreaseSpeed.Operate = cvTrue;

      

  R.IOLine = 7;

  R.Direction = cvOutput;

  R.Value = 0;

 

  com.Baud = cv9600;

  com.Operate = cvTrue;

 

  LeftServo.IOLine = 29;

  RightServo.IOLine = 30;

  RightServo.InvertOut = cvTrue;

  RightServo.Value = -20;

  LeftServo.Value = -20;

      

  LeftServo.Operate = cvTrue;

  RightServo.Operate = cvTrue;

 

  while(1)

  {

      

  }

 

}

 

Sub void Increase_Code(void)

{

       LeftServo.Value = LeftServo.Value + 1;

       RightServo.Value = RightServo.Value + 1;

       com.Value = LeftServo.Value;

       com.Value = RightServo.Value;

       R.Value = R.Value - 1;

      

}

 

Sub void Decrease_Code(void)

{

       LeftServo.Value = LeftServo.Value - 1;

       RightServo.Value = RightServo.Value - 1;

       com.Value = LeftServo.Value;

       com.Value = RightServo.Value;

       R.Value = R.Value - 1;

      

}

 

 

 

3. Avoid Obstacles with Infrared GP2D120

 

This first program enables the robot to avoid obstacles detected with one of the mounted infrared sensors – the Sharp GP2D120.

This sensor is fully supported by the OOPic IDE. It can determine the proximity of objects situated between 10cm and 80cm away from the robot.

This is the first step towards the complete avoid obstacles program.

 

Note: In order for the program to work correctly, the sensors should be put in the exact same positions and pointed at the exact same direction as when originally programmed.

 

avoid_obstacles_GP2D120.osc

  GP2D120.IOLine = 1;

  GP2D120.Center = 20;

  GP2D120.Operate = cvTrue;

 

  Running = 0;

 

   while(1)

   {

      /* Check if we have an obstacle in our way */

      Avoid_Obstacle(1);

   }

}

 

Sub void Avoid_Obstacle(Byte Dummy)

{

      

       if (Running == 0) return;

 

       RightServo.Operate = cvTrue;

       LeftServo.Operate = cvTrue;

 

       while (Running)

       {

      

              //condition "D"

              //it is enough to check for too close

              //right since it is common for all three situaions

              if (GP2D120.Value < TooClose_GP2D120)

              {     

                     //Rotate in place until RightMeasure

                     //is at DistanceFromLeftWall

                     //and LeftMeasure is biger than TooClose_GP2D120

                     RightServo.Value = -127;

                     while (GP2D120.Value < TooClose_GP2D120 )

                     {

                       //Rotate in place to the right

                       OOPic.Delay = 20;  //in 1/100 of second

                      

                     }     

                     RightServo.Value = 127;

              }

       }

 

       RightServo.Operate = cvFalse;

       LeftServo.Operate = cvFalse;

 

}

 

Sub void Go_Code(void)

{

   Running = 1 - Running;

}

 

 

4.  Avoid obstacles with GP2D120 and GP2D12

 

This program takes advantage of both sensors that the robot uses like eyes. The sensors differ in their range so they have to be initialized accordingly.

The performance of this program is important since it will show how adequate is the location and direction of each of the sensors which is key factor for the success of the avoid obstacles program.

 

oDio1 Y = new oDio1;

oDio1 R = new oDio1;

oDio1 G = new oDio1;

oEvent Go = new oEvent;

Byte Running;

oServoX LeftServo  = new oServoX;

oServoX RightServo = new oServoX;

oIRRange LeftMeasure = new oIRRange; //GD2D120

oIRRange RightMeasure = new oIRRange; //GD2D12

 

Const TooClose_LeftSensor = 90; //right wall 30cm

Const TooClose_RightSensor = 48; //left wall 30cm

Const DistanceFromLeftWall =  70; //about 50cm

 

Sub void Main(void)

{

  Y.IOLine = 6;

  Y.Direction = cvInput;

  oWire GoWire = new oWire;

  GoWire.Input.Link(Y);

  GoWire.Output.Link(Go);

  GoWire.Operate = cvTrue;

 

  R.IOLine = 7;

  R.Direction = cvOutput;

  R.Value = 0;

 

  G.IOLine = 5;

  G.Direction = cvOutput;

  G.Value = 0;

      

  LeftServo.IOLine = 29;

  RightServo.IOLine = 30;

  RightServo.InvertOut = cvTrue;

  RightServo.Value = 127;

  LeftServo.Value = 127;

 

  LeftMeasure.IOLine = 1;

  LeftMeasure.Center = 20;

  LeftMeasure.Operate = cvTrue;

 

  RightMeasure.IOLine = 2;

  RightMeasure.Center = 20;

  RightMeasure.Operate = cvTrue;

 

  Running = 0;

 

   while(1)

   {

      /* Check if we have an obstacle in our way */

      Avoid_Obstacle(1);

   }

}

 

Sub void Avoid_Obstacle(Byte Dummy)

{

      

       if (Running == 0) return;

 

       RightServo.Operate = cvTrue;

       LeftServo.Operate = cvTrue;

 

       while (Running)

       {

      

              //conditions "D","E", "F";

              //it is enough to check for too close

              //right since it is common for all three situaions

              if (LeftMeasure < TooClose_LeftSensor)

              {     

                     //Rotate in place until RightMeasure

                     //is at DistanceFromLeftWall

                     //and LeftMeasure is biger than TooClose_LeftSensor

                     R.Value = 1;

                     RightServo.Value = -127;

                     while ((RightMeasure.Value < DistanceFromLeftWall) & (LeftMeasure.Value < TooClose_LeftSensor))

                     {

                       //Rotate in place to the right

                       OOPic.Delay = 20;  //in 1/100 of second

                     }     

                     RightServo.Value = 127;

                     R.Value = 0;

              }

 

              //using "ELSE" - each cycle we do only one operation for smoothness

              else if (RightMeasure.Value < TooClose_RightSensor)

              {

                     //go slightly right

                     G.Value = 1;

                     RightServo.Value = -127;

                     while(RightMeasure < DistanceFromLeftWall)

                     {

                      OOPic.Delay = 10;

                     }

                     RightServo.Value = 127;

                     G.Value = 0;

              }

}

 

       RightServo.Operate = cvFalse;

       LeftServo.Operate = cvFalse;

}

 

Sub void Go_Code(void)

{

   Running = 1 - Running;

}

 

 

 

5. Avoid Obstacles – Complete

 

This is the final version of Avoid Obstacles. An improvement of the programs presented above that allows for demonstration of some independence. Here the robot uses the two sensors to let the robot navigate freely without hitting obstacles, as allowed by its sight.

 

avoid_obstacles.osc

oDio1 Y = new oDio1;

oDio1 R = new oDio1;

oEvent Go = new oEvent;

Byte Running;

oServoX LeftServo = new oServoX;

oServoX RightServo = new oServoX;

oIRRange LeftMeasure = new oIRRange;

oIRRange RightMeasure = new oIRRange;

Const TooCloseLeft = 48; //50cm

Const TooCloseRight = 92; //40cm

 

 

 Sub void Main(void)

 {

       //Initialize the button and wire

       Y.IOLine = 6;

       Y.Direction = cvInput;

       oWire GoWire = new oWire;

      GoWire.Input.Link(Y);

       GoWire.Output.Link(Go);

       GoWire.Operate = cvTrue;

 

       R.IOLine = 7;

       R.Direction = cvOutput;

       R.Value = 1;

 

       Running = 0;

 

       //Initialize left & right servos

       LeftServo.IOLine = 29;

       //LeftServo.InvertOut = cvTrue;

       LeftServo.Value = 127;

      

       RightServo.IOLine = 30;

       RightServo.InvertOut = cvTrue;

       RightServo.Value = 127;

      

       //Initialize left & right IR sensors

       LeftMeasure.IOLine = 1;

       LeftMeasure.Center = 20;

       LeftMeasure.Operate = cvTrue;

 

       RightMeasure.IOLine = 2;

       RightMeasure.Center = 20;

       RightMeasure.Operate = cvTrue;

 

      

 

       while(1)

       { //constanlty check if we are in the moving state

       if (Running)

       {

              //Start the servos

              LeftServo.Operate = cvTrue;

              RightServo.Operate = cvTrue;

      

       while (Running)

       {

       if (LeftMeasure.Value < TooCloseRight)

       {

              LeftServo.Value = -127;

              while (LeftMeasure.Value < TooCloseRight)

              {

                    

              }

              OOPic.Delay = 50;

              LeftServo.Value = 127;

       }

 

 

       else if (RightMeasure.Value < TooCloseLeft)

       {

              RightServo.Value = -127;

              while (RightMeasure.Value < TooCloseLeft)

              {

                    

              }

              OOPic.Delay = 50;

              RightServo.Value = 127;

 

 

       }

 

      

       }//end of while loop

 

       RightServo.Operate = cvFalse;

      LeftServo.Operate = cvFalse;

 

       }//end if

       }//end while(1)

             

 }//end of Main() function

 

 //control moving/not moving

 Sub void Go_Code(void)

 {

       Running = 1 - Running;

 }

 

6.  Move along the wall and avoid obstacles

 

Besides avoiding obstacles, through OOPic we can make the robot move following a certain pattern. Moving along a wall is a task that is applied often in practical tasks and theoretical problems, like the famous maze problem.

The solution presented includes a new task besides making sure that we do not hit any objects – to monitor a constant distance to the “wall” or set of objects which the robot is moving along.

Below the program listing is a set of diagrams that describe the scheme of the different cases that are used as basis for the solution.

 

keep_going_along_left_wall_and_avoid_obstacles.osc

oDio1 Y = new oDio1;

oDio1 R = new oDio1;

oDio1 G = new oDio1;

oEvent Go = new oEvent;

Byte Running;

oServoX LeftServo  = new oServoX;

oServoX RightServo = new oServoX;

oIRRange LeftMeasure = new oIRRange;

oIRRange RightMeasure = new oIRRange;

 

Const TooClose_LeftSensor = 90; //right wall 30cm

Const TooClose_RightSensor = 48; //left wall 30cm

Const DistanceFromLeftWall =  70; //about 50cm

 

Sub void Main(void)

{

  Y.IOLine = 6;

  Y.Direction = cvInput;

  oWire GoWire = new oWire;

  GoWire.Input.Link(Y);

  GoWire.Output.Link(Go);

  GoWire.Operate = cvTrue;

 

  R.IOLine = 7;

  R.Direction = cvOutput;

  R.Value = 0;

 

  G.IOLine = 5;

  G.Direction = cvOutput;

  G.Value = 0;

      

  LeftServo.IOLine = 29;

  RightServo.IOLine = 30;

  RightServo.InvertOut = cvTrue;

  RightServo.Value = 127;

  LeftServo.Value = 127;

 

  LeftMeasure.IOLine = 1;

  LeftMeasure.Center = 20;

  LeftMeasure.Operate = cvTrue;

 

  RightMeasure.IOLine = 2;

  RightMeasure.Center = 20;

  RightMeasure.Operate = cvTrue;

 

  Running = 0;

 

   while(1)

   {

      /* Check if we have an obstacle in our way */

      Avoid_Obstacle(1);

   }

}

 

Sub void Avoid_Obstacle(Byte Dummy)

{

      

       if (Running == 0) return;

 

       RightServo.Operate = cvTrue;

       LeftServo.Operate = cvTrue;

 

       while (Running)

       {

      

              //conditions "D","E", "F";

              //it is enough to check for too close

              //right since it is common for all three situaions

              if (LeftMeasure < TooClose_LeftSensor)

              {     

                     //Rotate in place until RightMeasure

                     //is at DistanceFromLeftWall

                     //and LeftMeasure is biger than TooClose_LeftSensor

                    

                     RightServo.Value = -127;

                     while ((RightMeasure.Value < DistanceFromLeftWall) & (LeftMeasure.Value < TooClose_LeftSensor))

                     {

                       //Rotate in place to the right

                       OOPic.Delay = 20;  //in 1/100 of second

                     }     

                     RightServo.Value = 127;

                    

              }

              //situation "C"

              //using "ELSE" - each cycle we do only one operation for smoothness

              else if (RightMeasure.Value < TooClose_RightSensor)

              {

                     //go slightly right

                    

                     RightServo.Value = -127;

                     while(RightMeasure < DistanceFromLeftWall)

                     {

                      OOPic.Delay = 10;

                     }

                     RightServo.Value = 127;

                    

              }

 

      

 

              //if there is no obstacle immediately forward and we are within reasonable deviation

              //from the DistanceFromLeftWall just go forward (do nothing)

              else if ((RightMeasure.Value > (DistanceFromLeftWall - 10)) & (RightMeasure.Value < (DistanceFromLeftWall + 2)))

              {

                     //no instructions; just keep going fwd

                     OOPic.Delay = 20;

              }

 

              //in case we are we are off course to the right

              else if (RightMeasure.Value > DistanceFromLeftWall - 10)

              {

                     //go left                 

                     LeftServo.Value = 10;

                     G.Value = 1;

                     //while we approach distance and there is no obstacle to the left

                     //continuosly go to the left. This can be changed later by going

                     //in small increments if it produces smoother movement

                     while((RightMeasure.Value > DistanceFromLeftWall) & (LeftMeasure.Value > TooClose_LeftSensor))

                     {

                           OOPic.Delay = 10;

                     }

                     LeftServo.Value = 127;

                     G.Value = 0;

              }

              //in case we are off course to the left

              else if (RightMeasure.Value < DistanceFromLeftWall + 10)

              {

                     //go to the right

                     Y.Value = 1;

                     RightServo.Value = -12;

                     while((RightMeasure.Value > DistanceFromLeftWall) & (LeftMeasure.Value > TooClose_LeftSensor))

                     {

                           OOPic.Delay = 10;

                     }

                     RightServo.Value = 127;

                     Y.Value = 0;

              }

       }

 

       RightServo.Operate = cvFalse;

       LeftServo.Operate = cvFalse;

}

 

Sub void Go_Code(void)

{

   Running = 1 - Running;

}

 

 

 

 

 

7. The PC Control application allows us to control directly the robot from the computer. Using the arrow keys on the keyboard we can make the robot go forward, backwards, go left, right, or turn in place.

 

There are actually two programs which we need: one is the host program on the robot, which receives the input from the computer, and carries out the necessary commands so that the robot goes in the specified direction. The other program is run at the computer linked to the robot. It accepts the user’s input and then creates output that is suitable for the robot to read.

 

It is important that the information for the user’s input arrives quickly. This will allow the robot the react promptly and produce smooth movement. For this purpose all the information for the user input is “packed” into one byte.