C++ Library for $50 Robot Version 1

As of 1 January 2009 this API has been deprecated. See here.

 

I have developed a library of C++ code which I have tested on an ATMega8 running at either 1MHz or 8MHz. Currently this supports the following kinds of object:

  1. Input pins
  2. Output pins
  3. LEDs
  4. Timer
  5. Analogue to Digital (ADC) input
  6. Servos running either off an output pin or via an output pin with PWM (pulse width modulation)

NB There is no UART functionality at the moment - but the classes above provide enough functionality to implement the $50 Robot Tutorial in C++. I will be extending the library to include classes for handling sonar, Sharp InfraRed, and H-Bridge control.

 

Attached is a ZIP file containing the source code for the classes for you to download. The second ZIP file contains some test code to perform the same functionality as the $50 Robot.

1 - Why another library and why in C++

If you are familiar with C++ and object orientated programming (OOP) then you may want to skip to the next section - or read the last <PROLOGUE> paragraph in this section. If you are new to these concepts then a brief overview now follows but remember that this is not a tutorial on how to program in C++ as you can 'google' for existing articles on this large subject.

 

So why C++?

 

Let's start by looking at a typical C program. This has one 'main' routine (ie the starting point) that calls various functions, or subroutines in BASIC parlence, which are either defined in the same file or are 'pulled in' via other header (*.h) files. So the program is very flat in structure - by which I mean that you could cut all of the code from all of the other files and paste them into one monolithic file which does everything (this is what the linker does for you - it merges code). If you do this you will notice that any of your functions can be called by any other code and that any of your variables can be read or written by any of the functions - everything is visible to everything.

 

Assume that you've been prototyping some new software and its all got quite big and complex and you have now decided that you want to get rid of the LED that you added on Port B5, say, for debugging purposes. So you now have to find all of the variables and functions that play with this LED and delete them - and this can mean wading through lots of code. The same thing would happen if you decide to move the LED to port B6 instead of B5. So the moral of this story is that the 'bigger' your code gets then the harder it becomes to maintain (let alone read and make sense of), and hence the increased chance of bugs arising in your code.

 

An interesting metric is that you will introduce a bug into your code for every 10 lines of new code that you write. (OK so this depends on the language etc etc - but is a fairly safe assumption that has been in use by software companies for ages).

 

So how do we make life a little bit simpler? In C you can create methods that deal with the LED. Here are 2 methods from the $50 Robot Tutorial which assume that the LED is attached to D4.

 

 

void LED_on(void)
{
PORT_OFF(PORTD, 4);//turn LED on
}
void LED_off(void)
{
PORT_ON(PORTD, 4);//turn LED off
}
These functions are useful because your main code may turn the LED on or off from lots of different places - so now you can shift the LED to D5 just by changing the two functions rather than every single place in your main code - since your main code just calls 'LED_on()' or 'LED_off()'. In OOP terminology we say that the functionality of the LED has been 'abstracted' - ie your main code doesn't care what pin the LED is connected to as it can continue to call 'LED_on()' and 'LED_off()'. OOP also says that the implementation of how the LED is turned off or on has been encapsulated into these two functions - ie they are the only places that actually know HOW to manipulate the LED. So in a C world then the use of functions is good because it allows our main code to be more abstract from the implementation and our main code is smaller and easier to understand.

 

OK so if functions are good then how does C++ help? To answer the question then lets start with a situation where C is not helpful.

 

Lets assume that rather than one LED you want to have, say, three LEDs on D4,D5 and D6. In C the easiest thing to do is to use cut and paste in your text editor so that you have an 'on' and an 'off' for each of the LEDs. So:-

void LED1_on(void)
{
PORT_OFF(PORTD, 4);//turn LED1 on
}
void LED1_off(void)
{
PORT_ON(PORTD, 4);//turn LED1 off
}

 

void LED2_on(void)
{
PORT_OFF(PORTD, 5);//turn LED2 on
}
void LED2_off(void)
{
PORT_ON(PORTD, 5);//turn LED2 off
}

 

void LED3_on(void)
{
PORT_OFF(PORTD, 6);//turn LED3 on
}
void LED3_off(void)
{
PORT_ON(PORTD, 6);//turn LED3 off
}

 

your main code can then do:

 

LED1_on();

LED3_off();

... etc

 

 

Yep - that will work! But when I used cut and paste to duplicate the functions then I had to be very careful to make sure that I changed the pin numbers so as not to introduce any bugs. Big deal you may think. Well since I can have 8 LEDs on port A, another 8 on port B, and another 8 on port C then I could have to cut and paste stuff 24 times if I wanted 24 LEDs!! However - we don't want to do this otherwise the 24 copies will take up valuable flash memory space for all this code and my program may not require all 24 LEDs.

 

Obviously the code to turn an LED on or off is very simplistic - consider how much code you would be duplicating if it was controlling something more complex like a servo which may, unlike an LED, also require other temporary variables !!

 

This is where OOP comes in.

 

The usual benefits of OOP are normally listed as 'encapsulation' and 'polymorphism' (amongst others see google). So I will now try to describe what they mean and why they are good.

 

If you think about it - the code to handle an LED, a Servo or most 'things' is basically the same - the only change is the controller pin that it is connected to. So in OOP we can define a 'class' (think of it as a 'thing') called an LED or a SERVO. This class contains the code that defines how that 'thing' works. The class would have 'methods' (which are the OOP version of functions that operate on the thing) called On() and Off(). When we want a new LED we can construct what is called a new 'instance' of that class, ie an actual LED, and at that point we say which pin it is connected to. So our main code can create LEDs on pins D4 and D8 by:

LED led1('D',4);

LED led2('D',6);

When these LED instances are created we store away the pin number (ie D4, or D6) in class variables which are invisible to the rest of the code and so cannot get corrupted. When we call:-

led2.On();

it knows to use the 'On()' code for 'led2' and it also knows that led2 is connected to D6.

 

Our 'main' code can create as many, or as few, LED instances as you want without introducing ANY more code. This is because the LED class encapsulates the functionality of how to turn an LED on or off. If there are any bugs in your LED code then you only need to change the code in the LED class as opposed to all the places that you cut and paste it to (eg the potential 24 LED functions in the C example listed previously).

 

This demonstrates one of the key components of OOP called 'encapsulation'. You can write all of the code for an LED in one class file that does the logic required. This code is hidden from the rest of the program - ie just call led1.On() - and it happens - you don't need to worry about how it does it. Other OOP languages call this an 'interface' or a 'contract'. Think of your 'contract' with the mail delivery service:- so long as you write the name and address on an envelope before putting it into a mail box then it will get delivered. You dont care if they use planes, trains, automobiles, bicycles or robots to do it - thats up to the mail company.

 

Astute developers will realise that you can achieve something like this in C by using a 'struct' to store the variables (like port and pin) for a given LED and then pass that to a generic LED_on or LED_off function - you are right but read on.

 

What about that complicated sounding 'polymorphism' thing? The standard analogy is to consider writing a drawing program on a computer. Lets assume that your program allows the user to draw circles and rectangles. So we will need two classes one called Circle and one called Rectangle. Each of these classes would need a method called 'draw' which draws the shape on the screen. But you probably want to be able to drag the mouse so that you can move the shape around the screen before drawing it. To do this you can draw the shape, wait for a mouse change and then 'clear' the shape at the old location before using 'draw' to draw it at its new location. So both of our brush shapes should have a 'clear' and a 'draw' method. Hey but this is the same for all shapes - if you can draw 'yourself' and clear 'yourself' then it doesn't matter what shape you actually are. So now we can create something called a 'Brush' which defines methods called 'clear' and 'draw' which don't actually do anything because the actual implementation depends on whether the brush is a Circle or a Rectangle - ie it adapts at runtime to call the method on the apppropriate thing.

So our main code for the dragging could look like this:-

void mouseDrag(Brush brush, int x, int y){

brush->clear(oldx,oldy); // clear the old brush

brush->draw(x,y); // draw the new brush at the new location

oldx = x; oldy=y; // remember the location for the next clear

}

This is called 'polymorphism' because this will work with ANY brush shape. If I create a new brush to draw an ellipse that has a 'clear' and 'draw' method then the above code will not need to change.

 

Shapes, drawing ? What has that got to do with robotics? Well instead of a 'brush' think of a motor that instead of clear/draw has a 'SetSpeed(int speed)' method. Instead of 'Circle', 'Rectangle' brushes I could create different sorts of motors eg a modified servo motor, a PWM controlled motor, an HBridge controlled DC motor but so long as they all have a 'SetSpeed' method that behaves the same then I could change between any of them without ANY code changes other than where I define the motor on the one line of my main program. Hence 'polymorphism' means that they are all motors and it is only at runtime that you need to say what kind of motor it is. Since they all behave the same, ie have the same set of methods, then they are interchangeable.

 

You astute C guys may say - "I can still do this in C". You're correct although it's now getting a bit more difficult for you. And its about to get harder...

 

At the start of this page we talked about merging all C code into one big file and how everything would be accessible to everything else. Lets concentrate on the Motor interface which just has methods to set the required speed and, maybe, to read the current speed. We discussed previously how this lets you drop-in different motor implementations without having to change you code. Well what if the motor code represented a DC motor via H-Bridge with Encoder feedback. Well the Encoder probably just helps to make sure that the 'SetSpeed(int speed)' method does what it says - but in order to do this it may require several variables to be remembered between calls and there may be other lumps of code eg 'int readEncoder()' all of which only apply to this sort of motor controller. In OOP you can create methods and variables with a given 'visibility' of 'public', 'protected' or 'private'. 'public' stuff can be accessed from anywhere. By 'accessed' I mean: if it is a method then it can be called from anywhere but if its a variable then it can be read/written from anywhere. 'protected' items can only be accessed by an instance of this type or by a derived class - ie a motor variable such as 'currentSpeed' can only be seen by a Motor or another kind of motor. A 'private' variable can only be seen by the same instance - so our Motor+Encoder example above may have a private variable for current encoder position which is not visible to anything except THAT motor.

 

So what's the difference? Well the 'public' methods define the interface/contract with the outside world - ie this is 'what you can ask me to do'. 'private' methods/variables are generally connected with how the class actually does things and since they are not visible to other code then they can be changed without any effect on the outside world. 'protected' methods/variables are a half-way-house in that if you create one in the Motor class then it is visible to anything that is a Motor but is invisible to anything else.

 

You astute C folk will realise that this is kinda where you have to throw in the towel as C cannot enforce visibility as it has no concept of it. I'm sure the real hard-core C folk will still want to beat me up as to how they can work around it but 'why bother' - C++ was designed to make life easier!  But why does 'visibility' matter? Well if everything is visible to everything, as in C, then it can make debugging a nightmare - eg if a variable value is getting changed unexpectedly then the culprit could be in ANY of the code. Whereas, if the variable in C++ is 'private' then the only code that can change it is the class that it belongs to. It also makes modifying code easier since a 'private' variable can only be accessed by the class then it means you can change the implementation code and add/delete/rename variables knowing that this wont upset any other code as it couldn't see the stuff you are changing anyway.

 

<PROLOGUE>

C++ adds some great stuff to make programming easier and more legible but there are times when it doesn't add anything above C, BASIC or Assembler. As we have seen above the ability to create new LEDs is very easy and you can create as many, or as few, as you like. However, once the thing you are trying to control has an interrupt then this benefit reduces down to the level of C. For example: a UART has receive/transmit interrupts that are different for each UART (most AVR processors only support 1, some support 2). So creating 5 Uart objects makes no sense. This is a hardware issue rather than the programming language - but if you can only create one instance of something then the C++ code approximates to the C code . The last question I guess is  - "So OOP constructs apart: then what else does this C++ library do for me". To which the quick answer is initialisation. Create one 'SERVOPWM' motor and the library will automatically set up PWM, equally if you define any A2D inputs then it will set up the A2D convertor. So your main code can concentrate on doing software stuff and delegate the hardware initialisation back to the library. Check out my Photophore code that uses the C++ library and you will see that there are NO calls to initialise things.

 

 

2 - Installation

Create a new folder (I'll assume it is called 'c:/SoR/C++') and unzip the C++.zip file to this folder making sure that your unzip utility is set to create the sub folders.

You should find that the following are created:

 

I have already compiled the library for you ( c:/SoR/C++/bin/cpplib.a ) so if you don't want to modify the library code then you dont need to do anything and can go to the next page to look at the $50 Robot Photovore code. Assuming you just want to try stuff out then just go to the next page now.

 

 

 

If you decide to change or add to the library then you can rebuild it by launching a DOS command prompt and typing :

 

CD c:/SoR/C++

 

To clean out all of the temporary files and force a recompile of the library then type:-

make clean

 

If you have just changed some of *.cpp or *.hpp file then you can recompile the library by typing:-

make

 

 

 

3 - Overview of the library (Part 1)

In.hpp

A class for defining input pins that can be either high or low.

You can create a new one at the start of your code by:

IN myPin('B',4,false); // creates an input on B4 with no pullup resistor

You test if a pin is low or high as follows:-

if(myPin.IsHigh()){

// The pin is high

}

 

if(myPin.IsLow()){

// The pin is Low

}

 

Out.hpp

A class for defining output pins that can be set high or low.

You can create a new one at the start of your code by:

OUT myPin('B',4,false); // creates an output on B4 and set it to low to start with

You can then change it to low or high with

myPin.SetLow(); // set it low

myPin.SetHigh(); // set it high

myPin.Set(true); // set it high

myPin.Set(false); // set it low

myPin.Toggle(); // If it was low set it high, if it was high then set it low

 

LED.hpp

This is a simple extension of OUT that has more friendly methods On() and Off(). You can also use the methods from OUT ie Toggle() will change the state of the LED.

 

Util.hpp

delay_cycles(volatile unsigned int cycles) is the same as the delay loop from the original tutorial in that it just pauses for a given delay.

 

int interpolate(int value, int minVal, int maxVal, int minRtn, int maxRtn) is a useful routine. This takes a 'value' that is known to be between 'minVal' and 'maxVal' and then returns a number in the range 'minRtn' and 'maxRtn'. So if you wanted to convert a number which is in the range 0 to 100 into a matching number in the range -255 to 255 you could just do:

int answer = interpolate(value, 0, 100, -255, 255);

 

int clamp(int value, int minVal. int maxVal); Will limit a value to the range minVal to maxVal. This is the same as writing:

if(value < minVal) value = minVal;

if(value > maxVal) value = maxVal;

 

The macros 'CRITICAL_SECTION_START' and 'CRITICAL_SECTION_END' can be used to surround a piece of time critical code. Since it disables interrupts then it shouldn't be used if the surrounded code takes a long time to run as you may loose some other critical interrupts.

 

Timer.hpp

You will normally create a timer at the start of your main code - see my Photovore code. And you should only create one of them! This implementation uses Timer2 and provides the following methods:-

unsigned long MsCur(); returns the number of milliseconds since power was switched on. Since an unsigned long can store a high value then it provides an effective 'time of day' clock. NB If your robot can be left switched on for a long period then you will have to take into account that this value may wrap around to 0.

 

bool HasElapsed(unsigned long msStart, unsigned in msWait); This will test if a given amount of time has passed. 'msStart' is a value you saved previously by calling MsCur() and 'msWait' is the number of milliseconds you want to check to see if they have passed. The method will return immediately with either 'false' if the period hasn't elapsed or 'true' if it has. This is useful with sensors such as sonars which should not be called without a reasonable delay between samplings so as to avoid ghost echoes. You can guard against this by saving the time when the sonar was last sampled. The next time it is called you can check that the minimum amount of time has elapsed since the last call and, if not, you could return the previously returned value.

 

void WaitMs(unsigned int ms); This will not return until the given number of milliseconds has elapsed. Note that this may be out by 1ms either way so it's not good for small numbers.

 

void WaitMs(unsigned int ms, unsigned long msStart); is similar to 'HasElapsed' except that it will not return until the given period has elapsed.

 

A2D.hpp

This is an extension of IN but for input pins that can do analogue to digital conversion. To create a new input pin on pin 4 just use:

A2D myIn(4);

NB This assumes port A (which is fine for Mega8 controllers) so attach your device to A4.

 

You can then read an 8 bit value via:

unsigned char value = myIn.ReadByte();

 

or a 10 bit value via:

unsigned short value = myIn.ReadShort();

 

Notice that you DON'T need to initialise the A2D convertor at all. Look at the file you will see the Init method that, by default, is called with some default values. If you want to use other values then you can call this Init method yourself BEFORE you create any A2D inputs. Since this is a static method it can be done by writing:

A2D.Init(ADC_PRESCALE.ADC_PRESCALE_DIV32, ADC_REFERENCE. ADC_REFERENCE_AVCC);

 

If you need to save power and turn off the A2D function then call:

A2D.Off();

You can turn it back on later by calling A2D.Init again.

 

 

 

4 - Overview of the library (Part 2)

 

Motor.hpp

A motor is an abstract extension of an output pin that defines some methods that apply to all motors such as:-

SetSpeed(int speed); // Can take a value from MIN_SPEED to MAX_SPEED

SetSpeed(int speed, bool forwards); // The first parameter specifies a speed from 0 to MAX_SPEED and the second parameter is 'true' for forwards, or 'false' for backwards.

GetSpeed(); // will return the last value of speed that was set (ie its not the true speed the motor is running at - you would need an encoder for that!)

 

The Disconnect(); method is like disconnecting the wires from the motor so it will cruise to a halt and, if on a hill, may then start rolling backwards. Whereas SetSpeed(0); will cause the motor to brake and hold on a hill. Motors can be reconnected at a later date with the Reconnect() method and you can test if a motor is connected via the IsConnected() method.

 

Servo.hpp

This extends the Motor class and implements it for a modified Servo as per the $50 Robot Tutorial. A new servo on port D2 can be created via:-

SERVO g_servoLeft( 'D', 2 , &g_timer, true, 1500, 300);

Note that you pass a reference to the global timer because the Servo code makes sure that at least 20ms has elapsed since you last sent it a command. If your motor is running in the wrong direction then change the 'true' parameter to 'false' - you don't need to change anything else. The last two parameters specify the pulse width to center the servo (ie 1.5ms) and how much the pulse width varies on either side of that value. NB The last 3 parameters are optional and if they are missing then they will be assumed to be false,1500,500 respectively.

 

ServoPWM.hpp

This class is for controlling a modified servo motor by using PWM. Otherwise it is identical to Servo.hpp except that it doesn't need the timer to be passed on creation.

 

5 - Photovore using the C++ library

Unzip the three files from the 'C++ Photovore.zip' file into another folder. I will assume its called 'c:/SoR/testCPP'. Here is a description of the files:-

 

main.hpp

This is the main header files that includes all of the required header files from the C++ library and from the avr library.

 

main.cpp

This is the main loop of the Photovore.

Line 7: 'TIMER g_timer' defines a timer that can be accessed in your own code but is also used by some of the library routines.

 

Line 9: 'LED g_led('D',1) defines an LED on D1

 

Lines 12 to 18: Either defines that you are using servos on D2 and D3 (as per the $50 Tutorial) or, if you uncomment line 5, will define that your servos are connected on B1 and B2 and will use PWM to set their speed. If you use the PWM route then make sure that pins B1 and B2 are connected to your motor supply rather than your +5v microcontroller supply.

 

The remaining code is very similar to the $50 Tutorial except:

Line 28: - stores the current time of day in milliseconds

Line 57: - waits until 20milliseconds has passed since the start of the loop.

 

makefile

The key entries in the makefile on lines 22 and 23. These should be changed to the microcontroller you are using and the clock speed. (The library currently only supports 1MHz and 8Mhz). NB If you change either of these values in the makefile then you will also need to change the same values in the makefile for the C++ library and then rebuild it using 'make clean', followed by 'make' - see Installation. If this becomes a real pain then you could rename each compiled library ie you could rename 'cpplib.a' to 'cpplib_Mega8_1MHz.a'.

 

Line 30: LIBS = c:\SoR\C++\bin\cpplib.a

This tells the linker to use the compiled code from the C++ library so you may need to change this to point to the folder where you have created it on your system.

 

Compiling your program

From a DOS/Command window - change to your project folder:-

CD c:/SoR/testcpp

 

Compile your program by typing:-

make

 

 

When the program is compiled you can upload the .hex file in the normal way.

 

6 - Tweaking the servos

If you have previously modified a servo then you may have noticed that their peformance can change depending, not only on how well you centered the pot, but also on external things like voltage levels etc.

To tune the code to your servo then you may need to fiddle with the following lines:-

SERVO g_servoLeft( 'D', 2 , &g_timer, true, 1500, 300);
SERVO g_servoRight('D', 3, &g_timer, false, 1500, 300);

The last 3 parameters do the following:-

true or false - indicates if one of the motors is flipped.

1500 - This represents the value to center the servo. In this case it means 1.5ms which is the default value for centering a servo.

300 - This represents the deviation on either side of the previous value. ie from 1.2ms to 1.8ms.

 

So to center your servos then change the last parameter to 0. This means that no matter what your code is trying to do it will always go at the speed set by the 1500 parameter. If 1500 doesn't keep your wheel stationary then tweak with the 1500 value until it does. You can then experiment with the second value so that you get the required variation in speed control. I then label each of my servos with the settings that works best for them.

 

The same thing applies if you are using the PWM version of the motor control.