Robot is Happy creating our robot overlords one day at a time

There are two forms of this advance Payday Loans UK But now, you have an extra
4Dec/090

Light-Seeking Robot using the Arduino by Christopher Hazlett

This is a repost from my (Chris's) old blog www.integratechange.com on May 5, 2009.

I've always been interested in physical computing. Even though I love creating software, I've always felt that creating websites and software doesn't go far enough to satiate my creative desire. Enter the Arduino, a great open-source micro processor and prototyping board for around $30. This post marks the first, in what I hope will be a long line of tutorials and projects using the Arduino to develop robots and sensor driven applications that I hope to release into the wild. This post details a light-seeking robot with an Arduino brain, kind of the "Hello World!" application for autonomous robotics.

The Parts

I got a number of parts from several different sources. I had some parts lying around, but I'll also provide links where you too can buy yourself all the light-seeking robot parts your heart desires.

Prototype I - Proof of Concept

While I was waiting for my chassis to arrive, I put together an initial prototype to test the circuit and code. The first prototype was rough, to say the least, and it didn't move, but the code worked. I used the prototype board you see in the picture (available at Radio Shack) as a base to mount (tape) the motors to. I put tape on the axles to see if the code was actually making the motors turn the right way. It was.

Initial Prototype and Code Testing Platform

And here's a video, showing it work in all it's glory.

As it says in the video, I initially gave the robot seeking and avoiding behavior (you can see it in the code below in the function foundSource()), but I realized that there are times when the robot will never find it's source (especially if that source is the sun) and that it was needless behavior. I left the runAway variable in the code through so you could easily turn the robot into a photophobe. You could also mount a switch on the robot that changes the behavior from photovore to photophobe as well.

Prototype II

Once I got the chassis from Pololu, I put together a better prototype, one that moves and turns around when it runs into something...you know, typical robot behavior. In the following pictures, you can see the very crude method of assembly, but it works...and that was really the point.
Prototype II on the Chassis
I literally moved the prototype board in the first picture above to the top of the chassis and hooked up the motors to the motor shield. I added a small switch for the motor power so I could stop screwing and unscrewing the motor's power supply. Everything is just taped down. This is, again, more of a proof of concept than a finished robot. I plan on making a custom motor driver for the chassis and better mount for the Arduino and other sensors.

Back-up sensor under the plow
To give the push button more surface area, I added a plow to the front, with an "ultra-strong" electrical tape hinge. Obviously, when the robot runs into something, it pushes the button and the turnAround() function executes.

Inside of the tracked chassis
There's not a lot of room in the chassis, but you could replace the AA battery pack with a 9V to give you some more space. But there are mounting holes on the corners which is probably a preferable location for your robot's brains.

Here it is in action:

The Circuit

The circuit is fairly simple, especially because I'm using the Motor Shield. This circuit diagram illustrates the sensor circuitry and status led you see on the white bread board above. The motors are attached to the M1 and M2 points on the motor shield (positive leads toward the inside of the board). I used OmniGraffle to draw up the circuit, but I'm still looking for better templates so my circuits are prettier, more accurate, etc, but this drawing should illustrate the connections just fine.

Light Seeking Robot

The Code

You program the Arduino in Wiring, which is basically a library in C++. Forgive me any trespasses below. C++ is not a language I've worked in a lot, and the code below could most likely use some optimization. I originally had many delays written into the loop because that's what I saw a lot of other code doing. That resulted in erratic behavior and a lot of running into stuff even though the object's shadow should have caused the robot to avoid it. When I removed the delay and averaged the light sensor readings, I got a very responsive robot. I've also left a lot of code in the source because I'm working on building a robot base that I can use over and over again as I install more sensors and create more interesting behavior.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include <AFMotor.h>
#define NUMREADINGS 5
#define LEFTSENSOR 3
#define RIGHTSENSOR 5
#define BUMPSENSOR 2
#define TOPSPEED 200
 
int i;
int valLefat;
int valRight;
int valCenter;
int oldLeft = 0;
int oldRight = 0;
int sensitivity = 40;
int threshold = 50;
int topThreshold = 650;
boolean runAway = false;
 
int leftReadings[NUMREADINGS];
int rightReadings[NUMREADINGS];
int index = 0;                            // the index of the current reading
int leftTotal = 0;                            // the running total
int leftAverage = 0;                          // the average
int rightTotal = 0;                            // the running total
int rightAverage = 0;                          // the average
 
AF_DCMotor rightMotor(2, MOTOR12_8KHZ); // create motor #2, 64KHz pwm
AF_DCMotor leftMotor(1, MOTOR12_8KHZ); // create motor #1, 64KHz pwm
 
void setup()
{
  Serial.begin(9600);
  rightMotor.setSpeed(TOPSPEED);
  leftMotor.setSpeed(TOPSPEED);
  pinMode(BUMPSENSOR, INPUT);
  moveForward();
  delay(500);
  for (int i = 0; i &lt; NUMREADINGS; i++){
    leftReadings[i] = 0;                      // initialize all the readings to 0
    rightReadings[i] = 0;
  }
}
 
void loop()
{
  checkForBump();
  averageReadings();
  checkLightandMove();
}
 
void checkLightandMove(){
  if(valLeft &gt; threshold &amp;&amp; valRight &gt; threshold){
    if((valLeft &gt; valRight) &amp;&amp; (valLeft - valRight &gt; sensitivity)){
      if(runAway == false){
        turnRight();
      }else{
        turnLeft();
      }
    }else if((valLeft &lt; valRight) &amp;&amp; (valRight - valLeft &gt; sensitivity)){
      if(runAway == false){
        turnLeft();
      }else{
        turnRight();
      }
    }else{
        moveForward();
    }
 
  }else{
    //turnAround();
    stop();
  }
 
  if(valLeft &gt; topThreshold &amp;&amp; valRight &gt; topThreshold){
    runAway = false;
  }
  //delay(500);
}
 
void checkForBump(){
  int bumped = digitalRead(BUMPSENSOR);
  Serial.println(digitalRead(BUMPSENSOR));
  if(bumped == HIGH){
    Serial.println();
    turnAround();
  }
}
 
boolean foundSource(){
  return oldLeft &gt; valLeft &amp;&amp; oldRight &gt; valRight;  //the robot has reached the source of the light, or the point of maximum brightness
}
 
void moveForward(){
  Serial.println("Move Forward");
  rightMotor.run(FORWARD);
  leftMotor.run(FORWARD);
}
 
void speedUp(){
  for (i=0; i==TOPSPEED; i++) {
    rightMotor.setSpeed(i);
    leftMotor.setSpeed(i);
  }
}
 
void slowToStop(){
  for (i=TOPSPEED; i==0; i--) {
    rightMotor.setSpeed(i);
    leftMotor.setSpeed(i);
  }
  rightMotor.run(RELEASE);
  leftMotor.run(RELEASE);
}
 
void turnLeft(){
  Serial.println("Turn Left");
  rightMotor.run(BACKWARD);
  leftMotor.run(FORWARD);
}
 
void turnRight(){
  Serial.println("Turn Right");
  rightMotor.run(FORWARD);
  leftMotor.run(BACKWARD);
}
 
void stop(){
  Serial.println("Stop");
  rightMotor.run(RELEASE);
  leftMotor.run(RELEASE);
  delay(500);
}
 
void turnAround(){
   slowToStop();
   delay(500);
   moveBackward();
   delay(2000);
   turnLeft();
   delay(2000);
   stop();
   //runAway = true;
}
 
void moveBackward(){
  Serial.println("Move Backward");
  rightMotor.run(RELEASE);
  leftMotor.run(RELEASE);
  rightMotor.run(BACKWARD);
  leftMotor.run(BACKWARD);
}
 
void averageReadings(){
  leftTotal -= leftReadings[index];               // subtract the last reading
  leftReadings[index] = analogRead(LEFTSENSOR); // read from the sensor
  leftTotal += leftReadings[index];               // add the reading to the total
 
  rightTotal -= rightReadings[index];               // subtract the last reading
  rightReadings[index] = analogRead(RIGHTSENSOR); // read from the sensor
  rightTotal += rightReadings[index];               // add the reading to the total
 
  index = (index + 1);                    // advance to the next index
 
  if (index &gt;= NUMREADINGS)               // if we're at the end of the array...
    index = 0;                            // ...wrap around to the beginning
 
  valLeft = leftTotal / NUMREADINGS;
  valRight = rightTotal / NUMREADINGS;
 
  Serial.print(valLeft, DEC); // prints the left sensor value
  Serial.print(" | ");
  Serial.println(valRight, DEC); // prints the right sensor value
}