Let's Make Robots!

Understanding the Mr. General Robot Kit

Navigates and tracks objects using Infrared
Mr_General_Nano.zip3.21 KB
Mr._General_4.bas17.22 KB
TDA2822m_stereo_power_amp.pdf141.68 KB
LM35_temperature_sensor.pdf303.72 KB
speakjetusermanual.pdf405.9 KB
Tone.zip9.68 KB
Mr__General_ATmega8_Edge_Detect.zip3.23 KB
Mr__General_ATmega8_Object_Detect.zip3.25 KB

Mr. General is based on my original LMR robot Bot 08M which was my attempt at a "Start Here" robot using the picaxe 08M processor. This walkthrough will explain how the sensors work, how the eye works, how the servos work and how the code works.

As of September 2011 we are releasing a new version which includes an ATmega8A, ceramic resonator, USB interface that can plug directly into the breadboard and a greatly improved manual. This interface can be bought seperately and should work with any Arduino clone that does not have an onboard USB interface. I have now updated this tip/walkthrough to include the new wiring diagram for ATmega8A as well as the new sample codes.

Note that there is one version of the code for object detection (your corner sensors aimed outward) and one for edge detection (your corner sensors face downward). In the case of edge detection you may need to use a black marker pen or some of the supplied heatshrink to reduce the sensitivity of the phototransistors (black). The sensitivity will depend a lot on the colour and material of the floor / table that the robot is running on.

Notice in the attachments is a new "Tone" library for the Arduino. This version, thanks to RobotFreak and Brett Hagman works on the ATmega8 as well as the other Arduino boards. The version in Arduino 0022 and earlier does not. Simply delete the old Tone library from the library folder and add this one instead. As later versions of the Arduino IDE have the tone command included you must add "#include <Tone.h>" to your code for this library to be selected.

The sensors:
In late 2008 Frits described a simple sensor using an LDR and one or more LEDs. This is a simple but effective sensor. More importantly he pointed out that your processor should take two readings, One with the LEDs on and another with the LEDs off. Then measure the difference! This will be explored later when we look at the code.

I expanded on this idea using phototransistors instead of LDR's as they are quicker to respond and using them in pairs to track movement. I ended up with this very simple IR motion tracker.

When you look at the corner sensors on Mr. General they are just a simple voltage divider. The principle is that the phototransistor works much like a LDR (light dependand resistor). As more light shines on the transistor it allows more current to flow. The voltage across the fixed resistor changes with the current flowing.

When the sensor is connected to a digital input then it will read as a 1 when the voltage goes above 60% of the CPU voltage and will read as a 0 when it falls below 40%. The actual voltage levels may vary slightly depending on the processor used. When connected to an analog input then the voltage will get higher as the object gets closer. The advantage of using the sensor on an analog input is that your code can then have more than one level. You might have:

  0 - 200       nothing there
  201 - 500    something there but no chance of collision. Curious? have a look.
  501 - 800    try to avoid this
  801 - 1023  better back up or something quick!

The Eye: consist of 4 sensors almost the same as those on the corners of the main PCB. The main difference being that there are two phototransistors in parallel. This doubles the sensitivity. Increasing the brightness of the IR LED could also increase the sensitivity but uses more power and flattens the batteries quicker.

Below is a full schematic of Mr. General using an ATmega8A. A schematic using the Picaxe 28X1 can be found further down. Click on the schematic for a full sized image which you can then save onto your computer.

Servos - how they work:
Mr. General uses two standard micro servos for the pan/tilt assembly that makes his head/neck. This pan/tilt kit was designed right here on LMR. These servos consist of a small motor, a gearbox and a variable resistor connected to the output shaft. A small built in control circuit uses the variable resistor to determine what position the output shaft is in. A control pulse tells the circuit where the shaft should be. The control circuit uses this information to adjust the speed and direction of the servo motor until the position of the output shaft matches the position given by the control pulse.

This pulse is between 1mS and 2mS in width with 1.5mS being the center position of the servo. The pulse repeats every 20mS. Different servo manufacturers have slightly different standards and as such some servos will work with pulse widths outside of the 1-2mS range. Pulses that exceed these limits may force your servo to try and move beyond it's range of travel and possibly damage the servo.

Continuous rotation servos:
Mr. General uses two continuous rotation servos for movement. A continuous rotation servo is similar to a standard servo except that the output shaft can rotate continuously. For this reason there is no variable resistor that monitors the position of the output shaft like there is in a standard servo. The variable resistor is replaced with two fixed resistors that simulate the variable resistor set to the center position.

Now a pulse of 1.5mS will make the motor stop. A pulse greater than 1.5mS will make the output shaft turn clockwise and a pulse less than 1.5mS will rotate the shaft counter clockwise. The closer the pulse width is to 1.5mS the slower the motor will turn. In reality no two servos are the same and as such 1.5mS is only the theoretical center position. Temperature can also affect this center position causing the motors to drift slightly in one direction on a cold morning and the other direction on a hot day.

To connect either type of servo to Mr. General simply plug it into the 3 pin male headers provided with the ground wire (usually black or brown) to the outer edge of the PCB. The 3 pin male headers already have power supplied (4.8V) so only a single wire is needed to connect the signal wire to the processor. All 3 pin male headers have a 3 pin female header connected in parallel so that a jumper wire can be used to connect the servo to the breadboard.

Programming Mr. General with the USB interface:
The USB interface from DAGU plugs directly into the breadboard. Because the sample code uses D0 and D1 for the pan servo and eye IR LEDs these must be temporarily disconnected when programming. Once the program is loaded the USB interface is removed and the pan servo and eye IR LEDs are reconnected.

Pololu may sell this kit with a similar USB interface. Use DTR for your reset. It is a good idea to use a 1K resistor in series with the TX and RX pins to limmit the current

Making a programming cable:
To program the ATmega8A while it is in the breadboard will require a homemade programming cable. There are many USB to serial interfaces available. The photo below shows a typical example of what you might find in an office supply store. Alternatively you could buy a USB/serial breakout board such as the FTDI basic from Sparkfun.

No matter which interface you use your cable will need 4 wires. Gnd, TX, RX and DTR or RTS. Normally I use DTR but if that doesn't work then try RTS. A full list of pinouts for the D9 serial socket can be found here: http://en.wikipedia.org/wiki/Serial_port

In order for the Arduino IDE to reset the ATmega8A prior to programming a 100nF capacitor needs to be in series with the DTR and reset pins. This capacitor allows the DTR pin to briefly trigger a reset allowing the bootloader to accept a new program.

I have shown 1K2 resistors in series with TX and RX. This is a simple precaution as D0 and D1 can be input or output depending on your program. D0 should be disconnected from the eye and D1 disconnected from the servo prior to program upload to ensure a reliable data transfer.

The Code:
The original "Mr. General" kit was designed around the Picaxe 28X1 although many different processors can be used. The program has since been re-written for Arduino and the kit is now normally supplied with the ATmega8A which is equivalent to the old Arduino NG with ATmega8.

If you have an Arduino Nano then this will also plug directly into the breadboard. The Arduino Nano has two extra analog input. This allows the 4 corner sensors to be used as analog sensors.

I have attached sample code for ATmega8A, Arduino Nano and Picaxe28X1. If you are using a Picaxe 28X2 or 40X2 then you might be able to use the X2 conversion wizzard to convert the program.

Arduino users should note that there is a seperate tab called "IO_pins.h" where all the IO pins are defined. This tab is effectively your wiring diagram as it tells you which pin of the processor connects to what piece of hardware on the PCB.

Regardless of which processor you use the structure of the code is very simple.

The Main loop does these things:
1. Updates the LED pattern aproximately 5 times a second. This causes the corner LEDs to chase around the PCB.
2. Updates the position of the neck servos and the speed / direction of the continuous rotation servos.
3. Reads the compound eye.
4. Calculate new pan / tilt servo positions and continuous rotation servo speeds to maintain object tracking.
5. Read the corner sensors and adjust continuous rotation servo speeds to prevent a collision.
6. Optional behaviour routines such as boredom counters can be added here.

Reading the IR sensors:
Simple IR sensors such as those used on Mr. General cannot measure distance accurately and can be tricked by objects of different colours. For example a small bright white object in the distance and a large dark object nearby can give the same readings depending on how well they reflect IR. Sunlight has a lot of infrared light an can easily trick or blind these sensors. Background light such as this is called ambient light.

To help overcome some of these limitations we use the method proposed by Frits of reading the sensors twice. The first time we read the sensor with the IR LEDs on. This gives us a reading that is equal to the ambient light plus IR LED light that has reflected from a nearby object. The second reading is with the LEDs off so that we read only the ambient light. When we subtract the second reading (ambient IR) from the first (ambient IR + reflected IR) we are left with a value that represents only the IR light that was reflected from a nearby object. This technique allows the robot to track your hand movements while ignoring the IR light coming in from a nearby window.

Tracking Motion:
Using the pan servo as an example the robot must first read the left and right compound eye sensors and subtract the ambient light as previously mentioned.

The distance/reflectivity of the object must be taken into account to prevent servo overcorrection. This is done by using a variable called panscale wich is the average of the left and right readings divided by LRscalefactor which is adjusted to allow for servo speed and tracking sensitivity. Too sensitive and the servos will overshoot causing them to jitter.

A value called "leftright" is the absolute difference between the left sensor and the right sensor divided by the panscale to allow for distance and servo speed. This value is then added or subtracted from the old servo position to provide a new servo position.

Tilting of the head works the same way as the panning of the neck. Arduino users must forgive the clumbsy code as it has been translated from Picaxe basic which has limited math functions and no negative numbers.

Following an object:
In order to track an object properly the robot needs to do more than turn it's head. It must follow with the body. If the neck pans too far left or right then the wheels are driven causing the robot to turn towards the object.

Distance is calculated by averaging the readings of all 4 sensors (up, down, left and right). This is not an accurate measurement of distance but is good enough for the robot to judge things such as which direction is blocked and which direction has room to move. The robot tries to maintain a set distance from the object it's tracking so as not to loose it's lock on the object while avoiding a collision. The wheels are driven forward or backward as required.

Collision avoidance:
Finally the PCB corner sensors are read in the same fasion as the eye sensors. One reading with the LEDs on and one with the LEDs off. This causes all the corner LEDs to pulse briefly. Because of the speed this is happening at the green corner LEDs appear to be dimmly lit.

After the readings have been taken any objects detected are compared with the direction of the motors. If necessary a motor will be stopped to avoid a collision.

Light pattern and sensor indication:
If a corner sensor detects an object or the light pattern determines that that corner LED should be on then that LED will be re-lit causing that corner LED to appear bright rather than dim.

Additional behaviour:
In the original picaxe code I also experimented with a boredom counter which monitored how much time had passed without tracking a moving object. If too much time passed then the robot would wander off in a random direction until it found a new object. If that object failed to move in a given time the robot would wander off again.

Add other counters to monitor things such as frustration if the robot gets stuck in a corner. Excitement if the the robot finds a fast moving object or multiple moving objects. By adding several counters and behaviour routines your robot can appear quite life like.

IR Communications:
If a suitable communications protocol was written then it should be possible for more than one robot to communicate with each other using the IR sensors as IR transcievers.


Picaxe version using the 28X1:  Click on the image below for a high resolution version that can be saved onto your computer.

The Picaxe basic code is actually the original code that the Arduino version was derived from and has some extra features. In the main loop there is a EdgeDetection subroutine as well as an ObjectDetection subroutine.

If you have your sensors pointing down to detect the edge of the table for example then detecting something with your sensors is good and the robot can move freely. If nothing is there then the robot must avoid the edge and the corner LED will light up.

If you have your sensors facing outward to detect objects such as a wall then detecting nothing with the sensors is good and the robot can move freely. If something is detected then the robot must avoid it and the corner LED will light up.

You must choose one subroutine and rem the other out depending on the configuration of your PCB corner sensors. The logic of these routines may be a little confusing as port C has been split with half of it configured as input and half as output.

Picaxe users will note I have included the resistors necessary for programming the picaxe 28X1. A 3.5mm stereo headphone socket with a few jumper wires soldered on will allow you to plug in a standard Picaxe programming cable. See the "Serial Download Circuit" shown in Manual 1 for more details.

Some Clever people like Gareth have made simple breadboard interfaces like this:

This photo was pinched from Gareth's Picaxxo project.

Resonators and Crystals:
Originally Mr. General (both Picaxe and Arduino) used a 3 pin, 16MHz ceramic resonator. This is the cheapest and easiest to use. There are 2 ways this can be installed on the breadboard. The first way is to plug it in near the chip and use 3 jumper wires to connect it to the processor. This usually works ok as long as the jumper wires are not too long.The tracks of the breadboard and the wires act like small capacitors and inductors. These can affect the frequency of the clock or prevent it functioning all together if there is too much.

I prefer to bend the legs of the resonator so that it connects directly to the pins of the processor. This is more reliable. As the resonator pins are a bit short it is even better if you solder some extensions onto the pins. Picaxe 28X1, ATmega8, ATmega168 and ATmega328 all have the GND pin (8) and XTAL pins (9, 10) in the same configuration making this easy.

If you are using Arduino then a 16MHz crystal and two 18pF or 22pF capacitors can be used for better timing accuracy. This might work with picaxe although I have never tried it.

Additional hardware:
The main PCB of Mr. General has all the spare space converted to prototype board. This area is ideal for adding additional circuitry such as line following sensors, speakjet chipset, amplifiers etc. There are 2 great "How to's" for the speakjet here:
http://letsmakerobots.com/node/4305 this is Ant's post using the picaxe.
http://letsmakerobots.com/node/13210 this is Droidbuilder post using the Arduino and TTS256 companion processor.

An ideal amplifier is the TDA2822M. This is a small 8 pin stereo power amplifier that will work with supply voltages from 1.8V to 15V. The two amplifiers in the chip can be connected in "bridge mode" to make a single amplifier with a greater power output. I have attached the datasheet which includes sample schematics showing how to use the amplifier.

As the continuous rotation servos stop position is sensitive to temperature, a temperature sensor such as an LM35 could be added between the servos. Your processor could use this to adjust the stop position of the servos.

Additional voltages:
You may choose to use 3.3V devices. The area under the breadboard is an ideal location for a 3.3V regulator. As the power rail on each side of the robot can be isolated and changed you could connect the rail on one side of the robot to 3.3V and switch all the servos to the other rail which might remain connected to battery +V.

I hope this guide will help owners of the "Mr. General" robot kit to get more enjoyment from it through a better understanding of it's functions.


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Your English is better than my Chinese and I live in China with a Chinese wife and son.

You should not really need these shields as the lens on the LEDs and sensor make them very directional with a sensing angle of about ±15°.

Your corner sensors would definitely need something between the LED and Phototransistor if you wish to use this method. At best you may gain a slight increase in range using my sample code because of the greater difference between ambient IR and reflected IR.

These are my first steps in "robotic world" (but not in software) and I have chosen this kit because of it possibilities and fact that it already contains corner sensors, motors and a pan /tilt system for a good price. And you have the choice of controller ...

I tried your system (toggle light on/off and take difference of values returned). It is really efficient.

The only strange thing I notice is for rhe IR Eye: Right and Up sensors are less sensible that Down and Left ones ...

(value = difference between 'light on' and 'light off' values read by analog input, diff = difference with average of four sensors value, dist is in cm, condition = ambiant light, object is a vertical white bristol sheet)  

dist Right   Down   Left   Up    
(cm) value diff value diff value diff value diff average
< 5 988 -2,25 988 -2,25 993 2,75 992 1,75 990,25
5 985 -1,5 987 0,5 989 2,5 985 -1,5 986,5
10 974 -1,25 975 -0,25 980 4,75 972 -3,25 975,25
15 798 -57,5 946 90,5 944 88,5 734 -122 855,5
20 567 -83,3 738 87,75 718 67,75 578 -72,3 650,25
25 477 -86,5 641 77,5 628 64,5 508 -55,5 563,5
30 380 -89,3 537 67,75 525 55,75 435 -34,3 469,25
35 310 -89,8 462 62,25 450 50,25 377 -22,8 399,75
40 264 -88,8 412 59,25 399 46,25 336 -16,8 352,75
45 232 -86,8 376 57,25 362 43,25 305 -13,8 318,75
50 209 -85 350 56 334 40 283 -11 294
> 50 150 -80,3 280 49,75 265 34,75 226 -4,25 230,25

I have verified twice and more my soldering, but it is correct ... Have you already noticied that ?

I start to write an arduino library for IREye and Corner sensors. If someone is interested, I will post it.



I am a little confused because you show values at greater than 50cm. Typically the sensor only works over a range of 20cm. Can you post some clear, close up photos of your compound eye from the front so I can check your sensor orientation?

It would be interesting to see how your readings compare with the heatshrink removed. I found it was hard to get the heatshrink to affect all sensors equally. If possible, post a second set of readings with it removed.


without my "bristol" shield

  without light shield      
dist (cm) up left down right average
< 5  1014 1014 1016 1016 1015
5 1003 1002 1006 1010 1005
10 1000 1000 1003 1003 1001
15 986 993 997 926 975
20 792 917 909 727 836
25 646 768 756 610 695
30 552 669 657 533 602
35 491 602 592 481 541
40 450 556 547 445 499
45 420 523 515 418 469
50 398 499 492 399 447
> 50 319 410 403 324 364

with my "bristol" shield...

  with light shield      
dist (cm) up (q7q8) left (q5q6) down (q3q4) right (q1q2) average
< 5  1012 1011 1015 1016 1013
5 1000 999 1004 1009 1003
10 998 998 1002 1006 1001
15 973 998 1002 903 969
20 678 813 791 691 743
25 519 648 621 569 589
30 421 541 515 490 491
35 356 469 445 434 426
40 311 420 397 398 381
45 279 384 362 370 348
50 255 357 335 349 324
> 50 170 262 240 272 236

Nota : For distance > 50 cm , obstacle was between 150 and 200 cm (it is a wood door of a "buffet") (same wood that the table where previous photos were made (teck))

measure was made with avoidance of incidente light from back and side, and obstable was a vertical sheet of white paper . (whitch explain imho the good values received ffrom "long" distance. Wood is also varnished.

It would seem your phototransistors are unusually sensitive. Most eyes are only sensitive for about 20cm. Experiment with the timing. A longer delay between when the LEDs turn on/off and when the sensors are read may give you more stable readings.

main program :
#include <IR_head.h>
IR_head tete;
long sum[4];
int i;
byte j;
int dist = 0;
int avg;
int nbl = 128;

void setup() {
  Serial.print("Debut de mesure (");Serial.print(nbl);Serial.println(')');

void loop() {

  for (j=0;j<4;j++) { // reset sum
    sum[j] = 0;
  for (i=0; i<nbl;i++) {
    for (j=0;j<4;j++) {
      dist = tete.get_raw(j);
      sum[j] += dist;
//  Serial.print(dist);Serial.print("\t");Serial.println(sum[j]);
  avg = 0;
  for (j=0;j<4;j++) {
    sum[j] = sum[j] / nbl ;
    Serial.print( sum[j]);Serial.print("\t");
    avg += sum[j];
  avg = avg/4;

library that I created for the IR eye :
// include this library's description file
#include "IR_head.h";
int _IRLIRt[4];
int _IRLled;
int _IRLthreshold;
// Constructor
IR_head::IR_head() {
void IR_head::attach(int ir_right,int ir_down,int ir_left,int ir_up,int led,int threshold) {
    _IRLIRt[CAPT_R] = ir_right;
    _IRLIRt[CAPT_D] = ir_down;
    _IRLIRt[CAPT_L] = ir_left;
    _IRLIRt[CAPT_U] = ir_up;
    _IRLled = led;
    _IRLthreshold = threshold;
// set threshold after init
void IR_head::set_threshold(int threshold) {
    threshold = constrain(threshold,0,1023);
    _IRLthreshold = threshold;
// get_raw value of one of the IR transistor
int IR_head::get_raw(byte direction) {
    int val;
    direction = constrain(direction,0,3);
    val = analogRead(_IRLIRt[direction]);
    val = val - analogRead(_IRLIRt[direction]);
// get_raw_average value of all IR transistor
int IR_head::get_raw_average() {
    int val;
    val = (analogRead(_IRLIRt[0])+analogRead(_IRLIRt[1])+analogRead(_IRLIRt[2])+analogRead(_IRLIRt[3]))/4;
    val = val -((analogRead(_IRLIRt[0])+analogRead(_IRLIRt[1])+analogRead(_IRLIRt[2])+analogRead(_IRLIRt[3]))/4);
// get_danger  return true if val > threshold
int IR_head::get_danger() {
    int val;
    val = get_raw_average();
    return(val > _IRLthreshold);

As you can see, there is a delay of 2 ms between light on/light off and analog read, and values printed are the average of 128 sensor read.
Perhaps there is an error in algorythm. These are my first try with arduino langage an microcontroller world ...
I will experiment with longer delay between light on/off and analog read to see if results are different or in the same scale
EDIT : Here is the result with temporization of 25 ms between light on/off and analog read:
Debut de mesure (128)
dist 1      2     3     4     avg
50   221 317 320 310 292
45   247 347 349 333 319
40   279 382 384 361 351
35   320 429 429 397 393
30   379 494 494 446 453
25   465 587 587 514 538
20   616 746 752 634 687
15   831 880 932 796 859
10   969 971 976 977 973
5     973 974 979 984 977
0     982 984 991 992 987

Front :

Back :

Notice that the varnish was already broken before I start to solder ...






I bougnt Mr General and build it with a arduino nano. It si a great kit, as it permits to change or add some parts using the pan/tilt system (ping system for example)

My question is about IR detection in corners and IR eye.

I made some lights isolator to avoid direct lighning between IR leds and photo transistors like this:

mr general ir corner

(IR led is "light isolated" with heaththrink and maintened with "chaterton" to the transistor to have both looking at in the same direction)

Do you think it is a good idea? Is there a need to have a minimal distance between the led and transistor? (they are close to each other)

For IR Eye, I used another technic :

I build a screen in stong paper (bristol) to put around the four IR leds.

IR Eye light isolation

In this manner, the four leds are light isolated with a unique shield. Does it seems correct to you?



(sorry for my english, I am french ...)






The robot will spin around if you have not set the stop values correctly. Please give us more information. You say the noise changes when you hand is in front of it but you have not said if the robot turned it's head to follow your hand or perhaps looked away from your hand. A video of your robot would be helpful.