Arduino Robots – A First Attempt!
Hey Arduinoists everywhere! I am proud to proclaim that I am now one of you!!
The Arduino hardware/software platform is awesome in so many ways and has made my job of entry level robot designer much easier! Let me add that I didn't have any prior experience with building robots. This project has helped me quite a bit to jump start the process. While I still have a lot to learn, I can say that I have very quickly acquired a pretty good base to continue building on. It’s exciting and fun! And so, this is the main reason I am posting this blog entry. Read on …
Making Robots
As I mentioned above, this is the first time I have ever attempted an electronics project of this complexity. I had built a simple timer circuit when I was younger, but not much beyond that. Having a casual interest in robotics for a while, I never felt like I had access to the right tools and tech to approach the subject until I heard about the Arduino microcontroller. I read a bit about what people where doing with them online, watched about a hundred Youtube “Hey I Made a Segway Arduino Robot” videos, and then ordered a few boards, sensors and other starter kit stuff. Once the orders arrived at my doorstep, I commenced to begin the basic exploration via the numerous examples available all over the web. Progressing through, blinking LED’s, onto LCD panel output, and then to the PING)) and Compass sensors.
Although I had a general idea in mind for the mechanical bits, I didn’t really know the best way to go with the microcontroller. My robot (dubbed botZero) grew organically. I worked on particular example problems first and then started connecting parts later. Those boards and pieces of example sketches (Arduino programs) later became my current hardware/software prototype.![]()
Before I go into the details of this design and it’s construction, I want to make reference here of useful resources for beginning Arduino users:
http://arduino.cc ... the master site of the Arduino platform.
Retail websites I used for parts: MakerSHED , Hacktronics
NKC Electronics All Electronics Adafruit Pololu Robot Shop
Design and Construction
About how I first approached the design of this robot ... I didn’t really have a good plan in my head until after I finished a prototype board assembly with the PING and Compass sensors. Once I saw those numbers appear on the LCD panel I rigged, I immediately imagined using that data to steer a three-wheeled robot. Three wheels? Why three? Because, the steering assembly construction appeared to me to be much less complex for a single steering wheel. Plus, I wanted to build it by hand, instead of ordering some chassis kit and assembling that. Don’t get me wrong, those assembly kits seem like great ways to quickly get your project up and running mechanically. But for myself, I was just as interested in the mechanics as in the electronics and control software, so I decided on the tricycle platform for ease of construction.
Now onto the electronics! I will cover the most fundamental points first. At the heart of this design is a pair of Arduino Duemilanove microcontrollers, linked together by a simple serial connection. My robot could have been constructed with a single Arduino board, however, I wanted to make sure I had plenty of room for growth (servos, motors, and various sensors and other micro-peripherals) in the future. Also, I liked the idea of separating the platform into sensor data acquisition and motion control for a more componentized organization. The only problem here is, you can’t just *snap* two of these boards together to make a larger one. They both operate on separate clocks – therefore, I had to create a simple handshaking algorithm for data exchange between the two boards. This was not hard, as like most other things Arduino, there was a good example already on the Arduino site. I will cover the details of the serial communications and handshaking code in a later post, for now let me just say, cross the TX/RX lines and MAKE THAT COMMON GROUND!!
Boards, Sensors, Motors
Now looking at the two Arduinos used in this design, you can see the top most board on the robot is the sensor board. It is connected electrically to a PING))) ultrasonic sensor(ultrasonic echo location chip) and a Hitachi compass module(magnetometer chip). It takes samples from these chips for distance and direction. After each read from these sensors, the data is sent over the serial connection to the second Arduino, the motor control board.
Here is a partial sketch (Arduino program) illustrating the sample collection from the PING)) Sensor : Note: this code does not show the data communication from the sensor board to the motor control board. That code is contained in complete source archive below. |
1: // PING))) 2: // the pin number of the sensor output 3: const byte pingPin = 7; 4:
5: // sensor data values 6: int inches = 0; 7: int cm = 0; 8:
9: // PING Sensor driver logic 10: void pinger_loop() 11: {
12: // variable for duration of the ping 13: long duration; 14:
15: // The PING))) is triggered by a HIGH pulse of 2 16: // or more microseconds. Give a short LOW pulse 17: // beforehand to ensure a clean HIGH pulse: 18: pinMode(pingPin, OUTPUT);
19: digitalWrite(pingPin, LOW);
20:
21: delayMicroseconds(2);
22: digitalWrite(pingPin, HIGH);
23:
24: delayMicroseconds(3);
25: digitalWrite(pingPin, LOW);
26:
27: // The same pin is used to read the signal 28: // from the PING))): a HIGH pulse whose duration 29: // is the time (in microseconds) from the sending 30: // of the ping to the reception of its echo 31: // off of an object. 32: pinMode(pingPin, INPUT);
33: duration = pulseIn(pingPin, HIGH);
34:
35: // convert the time into a distance 36: inches = microsecondsToInches(duration);
37: cm = microsecondsToCentimeters(duration);
38: }
39:
40: // PING Scale Functions 41: long microsecondsToInches(long microseconds) 42: {
43: // According to Parallax's datasheet 44: // for the PING))), there are 73.746 45: // microseconds per inch (i.e. sound 46: // travels at 1130 feet per second). 47: // This gives the distance traveled 48: // by the ping, outbound and return, 49: // so we divide by 2 to get the 50: // distance of the obstacle. 51:
52: return microseconds / 74 / 2; 53: }
54:
55: long microsecondsToCentimeters(long microseconds) 56: {
57: // The speed of sound is 340 m/s 58: // or 29 microseconds per centimeter. 59: // The ping travels out and back, so 60: // to find the distance of the object 61: // we take half of the distance traveled. 62:
63: return microseconds / 29 / 2; 64: }
|
The motor control board also has an Adafruit motor shield attached, which handles all motor and servo control. This motor shield came as a kit in a static bag with some 25+ parts (chips, resistors, capacitors, PCB, etc). I was happy to have successfully soldered the whole together, being that this was my first major small electronics soldering project. The motor shield is supplied an external 9.6 vdc Ni-MH supply that is used for motors control only, servos are still driven off the main onboard 9 vdc supply.
The motor control board is also the main Arduino holding all the control logic which drives user switch input, sensor servo, speed and steering decision control. Here is a partial sketch, containing the steering servo and motor speed control logic:
1: // DC motors on M3 & M4
2: AF_DCMotor motorLeft(4);
3: AF_DCMotor motorRight(3);
4:
5: // DC hobby servos
6: Servo servoSteering;
7: Servo servoSensor;
8:
9: byte inches = 0;
10: byte inches_ahead = 0;
11: byte inches_left = 0;
12: byte inches_right = 0;
13: byte angle = 0;
14: byte inches_steering = 0;
15: byte inches_minimum = 99;
16:
17: int steeringAngle = 70;
18: int sensorAngle = 70;
19: int sensorStep = -65;
20:
21: boolean stopped = true;
22: int stoppedTimer = 0;
23: int motorSlice = 0;
24: int sensorSlice = 0;
25: byte motorMode = RELEASE;
26: int dirchange = 0;
27:
28: const int ledPin = 15;
29: boolean stateChanged = false;
30: int lastState = HIGH;
31: int state = LOW;
32:
33: const int saverPin = 14;
34: boolean superSaver = false;
35: boolean highSpeed = false;
36:
37: const int SAVEBATTERY_SENSORSLICE = 64;
38: const int SAVEBATTERY_MOTORSLICE = 128;
39:
40: int sensor_timeSlices = -1; // disabled
41: int motor_timeSlices = -1; // disabled
42:
43: const int stopSpeed = 0;
44: const int fwdSpeed = 60;
45: const int backSpeed = 60;
46: const int turnSpeed = 70;
47: const int backSpeed2 = 70;
48:
49: // called from the Arduino Setup fcn
50: void InitMotorsAndServos(int angle, int mode)
51: {
52: sensorAngle = steeringAngle = angle;
53: motorMode = mode;
54:
55: // init servos
56: servoSensor.attach(9);
57: servoSensor.write(sensorAngle);
58: servoSteering.attach(10);
59: servoSteering.write(steeringAngle);
60:
61: // init motors
62: motorLeft.setSpeed(0);
63: motorRight.setSpeed(0);
64: motorLeft.run(motorMode);
65: motorRight.run(motorMode);
66: }
67:
68: // called from the Arduino Loop fcn
69: void motors_loop()
70: {
71: motorLeft.run(motorMode);
72: motorRight.run(motorMode);
73:
74: if (dirchange > 0)
75: {
76: dirchange--;
77: if (dirchange==0)
78: {
79: if (motorMode == BACKWARD)
80: motorMode = FORWARD;
81: else if (motorMode == FORWARD)
82: motorMode = BACKWARD;
83: }
84: return;
85: }
86:
87: change_motorsAcel();
88: }
89:
90: void change_motorsAcel()
91: {
92: if (stoppedTimer > 0)
93: {
94: stoppedTimer--;
95: return;
96: }
97:
98: if (motorSlice < motor_timeSlices)
99: {
100: motorSlice++;
101: return;
102: }
103: motorSlice = 0;
104:
105: if (stopped == false)
106: {
107: if (inches_steering < 10)
108: {
109: motors_forward(stopSpeed, steeringAngle);
110: }
111: else if (inches_left > inches_right && inches_left > inches_ahead)
112: {
113: inches_steering = inches_left;
114: motors_forward(turnSpeed, 5);
115: }
116: else if (inches_right > inches_left && inches_right > inches_ahead)
117: {
118: inches_steering = inches_right;
119: motors_forward(turnSpeed, 135);
120: }
121: else
122: {
123: inches_steering = inches_ahead;
124: motors_forward(fwdSpeed, 70);
125: }
126: }
127: else // stopped == true
128: {
129: if (inches_left > inches_right && inches_left > inches_ahead)
130: {
131: inches_steering = inches_left;
132: if (inches_steering < 5)
133: {
134: motors_backward(backSpeed, 135);
135: dirchange = 3200;
136: }
137: else
138: motors_forward(turnSpeed, 5);
139: }
140: else
141: if (inches_right > inches_left && inches_right > inches_ahead)
142: {
143: inches_steering = inches_right;
144: if (inches_steering < 5)
145: {
146: motors_backward(backSpeed, 5);
147: dirchange = 3200;
148: }
149: else
150: motors_forward(turnSpeed, 135);
151: }
152: else
153: {
154: inches_steering = inches_ahead;
155: if (inches_steering < 5)
156: {
157: long r = random(0, 2);
158:
159: motors_backward(backSpeed2, (r==1 ? 135 : 5));
160: dirchange = 3200;
161: }
162: else
163: motors_forward(fwdSpeed, 70);
164: }
165: }
166: }
167: // motors acceleration
168:
169: void set_motors(int mode, int limit)
170: {
171: int spd = limit;
172: if (highSpeed)
173: spd = (spd*15)/10;
174:
175: motorMode = mode;
176: if (limit <= 0)
177: motorMode = RELEASE;
178:
179: motorLeft.run(motorMode);
180: motorRight.run(motorMode);
181: motorLeft.setSpeed(spd);
182: motorRight.setSpeed(spd);
183:
184: // stopped timer check and set
185: stopped = (limit<=0);
186: if (stopped)
187: stoppedTimer = 1000;
188: }
189:
190: void motors_forward(int limit, int angle)
191: {
192: steer_toward(angle);
193: set_motors(FORWARD, limit);
194: }
195:
196: void motors_backward(int limit, int angle)
197: {
198: steer_toward(angle);
199: set_motors(BACKWARD, limit);
200: }
201:
202: void steer_toward(int sangle)
203: {
204: steeringAngle = sangle;
205: servoSteering.write(140-sangle);
206: }
The Almost Finished Robot
BOTZERO !
Here is botZero, as it is right now … more mechanics refactoring is left for the near future, as I plan to install a front wheel encoder. I want to use this to measure distance traveled and experiment with dynamically constructing a presence map for navigational control. By that I mean, collect historical obstacle distance and heading samples and adjust those values over time based on position changes calculated from wheel encoder data.
Parts assembled on this robot:
2x Arduino Duemilanove
1x Adafruit Motorshield Kit
1x PING))) Ultrasonic Sensor
1x Hitachi HM55B Compass Module
1x Green LED
1x Mini single pole toggle switch (3-5A)
2x Small hobby servos (salvaged from my crap helicoptor)
1x Tamiya Double Gearbox Kit (70168)
2x Tamiya Narrow Tire Set 70145 (4 tires total)
1x Custom build steering fork assembly (found junk furniture caster and scrap aluminum)
1x 4" x 8" Thin sheet aluminum
1x PCB board (radio shack)
2x 9-volt battery holders
1x 9.6 volt NiMH rechargeable battery pack (purchased at local hobby shop)
1x Plastic Box (TB-3)
Complete source available here.