Let's Make Robots!

modullo [Modular Robotic Platform]

This is modullo, one of my first elaborated robotic platforms. It hasn't got an actual purpose yet, I'm at the stage of adding various sensors and integrating them into a functional system.

The main design of the platform revolves around the concept of modularity. Each function of the robot is being taken care of by a separate microcontroller, while the main microcontroller, the ATMega16 (which is going to be replaced with an Digilent Nexys 2 FPGA when more processing power would be needed) communicates serially with each of the "peripherals" and processes all the inputs and outputs according to its final purpose.

The development platform is a Dagu Rover 5 tracked platform, which has 4 motors and 4 wheel encoders. The torque developed by the motors is enormous, the tracks are very grippy and the quadrature encoders offer 333 steps / revolution. It has some flaws, such as the fact that the current limiting of the IR LEDs of the wheel encoders is too low and the 1K resistor had to be replaced with a 500ohm resistor (or by 2 parallel 1K resistors) in order for the encoders to work properly. Another flaw would be the fact that the tracks occasionally come off when the platform rotates around its axis on a rough surface. All in all, it's a very good platform for its value.

All the microcontrollers are being programmed using the BASCOM AVR IDE, a home-made USBTiny programmer that uses an ATTiny2313 microcontroller and, of course, the already popular AVRDude programming tool.

Now I will briefly describe the modules installed at the moment on the platform.

1. The main board - using an ATMega16 microcontroller, running at 16 MHz

The main board sends and receives serial data to/from the other boards, along with receiving serial data from the radio module. The communication with the peripheral boards is done at a baud rate of 57600 bps and triggered by interrupts corresponding to each board. The main board triggers the interrupts, while each peripheral board sends/receives the data when the interrupt is triggered. The UART used for communicating with the peripherals is software (emulated), not hardware. The hardware channel is used for receiving data from the radio module (and, after further development, for sending back data to a master computer). The speed of radio communication is 4800 bps, quite slow, but the only option with the current modules. They also work at a baud rate of 9600 bps, but their range and sensitivity is greatly empaired.

This board will be, at some point, replaced by a Digilent Nexys 2 FPGA, which provides a far greater memory and processing speed, along with more than 100 input/output ports. All this processing power comes with the cost of a more complicated but cleaner and more popular programming language, the VHDL.

2. The motor controller - using an ATTiny2313 microcontroller, running at 16 MHz and 2x L298 motor drivers

The motor controller board microcontroller receives two bytes of data, one for each motor. It computes the PWM timing values and the direction bit and sends the output to each of the two L298 motor drivers. The PWM is, again, emulated, at a frequency of ~1 kHz. The chosen frequency is arbitrary, but it has lead to good results so far. Each L298 motor driver is able to drive two motors, so each L298 driver is used for a pair of motors on each side of the robot. There are also some indicator LEDs on the motor controller board: 4 of them are driven by the same PWM signals that drive the L298 drivers, while one of them blinks at each new data set received from the main board. Another LED indicates that the H-Bridges inside the L298 drivers are powered.

3. The power unit

It is basically a bunch of linear voltage regulators. There are 3x LM7805 5V regulators and one TS1086 3.3V regulator along with some failsafe diodes and an indicator LED. The 5V regulators power the microcontrollers, while the 3.3V regulator is used by some sensors, such as accelerometers or gyroscopes, that require this voltage. I used 3x 5V regulators because they tend to overheat even when used at low currents, so by splitting the total drawn current through 3 separate regulators, this minor problem can be neglected.

4. The battery charge level display - using an ATMega8 microcontroller, running at 12 MHz

This unit is being connected directly to the battery pack and it has its own LM7805 regulator. As the voltage provided by the Ni-Mh battery pack floats between a value over 8.4V when fully charged and 6V when fully discharged, the voltage across the battery pack is splitted over a voltage divider before being read by the ATMega8 on one of its ADC channels. The ADC value, corresponding to half of the battery pack voltage, is compared to the values corresponding to the fully charged / fully discharged and 6 intermediate intervals. The charge level is displayed using 8 LEDs which light up corresponding to the charge level. When it is fully charged, all the 8 LEDs are lit and when it's fully discharged, only the last LED is lit. The charge capacity is, of course, not a linear function of the output voltage, but a rough estimation of the charge level can be easily provided by the unit.

UPDATE: I have replaced the battery meter unit with an analogue 0-15V DC voltage meter. This unit will be replaced later on with another one based on an ATTiny26 or even ATTiny25/ATTiny13 microcontroller and some low-power LEDs (probably SMD).

5. The motor encoder manager - using an ATTiny2313 microcontroller, running at 16 MHz

This unit reads the inputs from two of the wheel encoders (one on each side). The microcontroller reads the quadrature grey code, computes the direction of rotation (displayed using 2 of the 4 LEDs for each side), measures the interval spent between two rotational steps for each side and then sends all the information serially to the main board. The main microcontroller will recalculate, using a PID algorithm, the command bytes that are being sent to the motor controller board so that the robot moves as it is supposed to. It will also send back to the computer all the information so that I could trace the route of the robot. This board is still under development, along with the PID algorithm needed for precisely controlling the speed and direction of the robot.

Update: I'm having a hard time dealing with the wheel encoders and with the PID algorithm. I managed to process the encoder informations, but the PID constants are still a mistery and the robot handles a bit weirdly. Working on it.

6. The USB Remote - using a PL2303 USB-Serial converter, a MAX232 level shifter and a 868 MHz radio module

The USB Remote is a small device plugged into any USB port of the computer and that allows the robot to be remotely controlled using a computer. The data sent via the USB port is converted to a RS232 signal, then to a 5V TTL UART signal that is being fed to the radio module. The PL2303 USB-Serial converter requires no special driver. I should mention that I'm using Ubuntu for all the robotic applications. At the moment, the protocol used by the remote allows the control of the robotic platform motors with a precision of 8-bit (7-bit per direction + direction bit), 4 additional 8-bit channels for various proportional-movement components, such as servos and 8 digital channels for triggering various devices. The software used for actually controlling the robot through the remote is developed using the SFML C++ library and the Code::Blocks 10.05 IDE.

7. The 8-channel servo controller - using an ATTiny2313 microcontroller, running at 16 MHz

The unit receives 8 bytes from the master unit, each corresponding to a separate servo channel. Then, the software computes the time variables for each servo channel and generates the PWM signal for controlling the servos. There are two additional 47 uF capacitors on the board, because of the noise generated by the electric motors inside the servos. For the moment, the unit is only used for controlling the servo used for detecting front obstacles. Later on, the detector will be used to do a proper mapping of the surroundings. 


1. The IR Radar system - using a Futaba S3003 servo and a Sharp GP2Y0A21YK0F IR sensor (10-80 cm range)

For the moment, the radar-like system is used for detecting front obstacles. It sweeps between 3 positions (-45 deg, center, +45 deg) and detects any forward obstacles. Later on, the radar will be used to sweep a complete half-circle area in front of the robot in order to create a map. The output of the Sharp IR sensor is fed directly to one of the ADC channels of the main board.

I also use a 4x20 LCD display, connected to the main board. Its main purpose is debugging and it will mostly likely be taken off the robot when its development ends. At the moment, it displays the values of the motor command bytes received from the computer.

Feel free to post comments concerning my project, to give me feedback and ideas or to ask me further details.


02-Oct-2011 --- UPDATE --- New level installed :D

About a week ago, I bought an Asus eeePC 1001px motherboard and an appropriate 6-cell battery that will further represent the brain of modullo. I installed xUbuntu 10.04 on an 8GB USB memory stick and stripped down all the useless applications. For now, the OS uses about 3 GB, leaving about 5 free GB of space. All the developed software is saved on a 2 GB SD Card, so that I could reinstall/change the OS after a while with no complications. This new module, the eeepc, is placed on top of the robot, leaving plenty of room underneath for easily accessing the electronics. Later on, I will provide it with a nice housing and it will be placed as low as possible, so that the total height of the robot will be as small as possible. Of course, I needed an USB hub as the motherboard only had 2 USB ports. When the robot is in the "development mode", both the mouse and keyboard are connected on USB ports, along with the memory stick and the type-B USB cable that provides the communication with the ATMega16 microcontroller.

The main reason for which I used a computer on the robot would be the advantage offered by the flawless WLAN or even Mobile Internet bidirectional data transfer. No more package losses, no more interference and neglictible lag (as I used UDP instead of TCP/IP). I used the SFML library for communicating (for the moment, only for that) with the master eeePC (a trusty 1005p that I used almost daily at the university last year) and the RS-232 library for the USB - ATMEL communication. I "upgraded" to a proper library instead of communicating using more-or-less appropriate stdio functions because it provides clear and simple to use functions. 

In order to control the robot, I use an USB remote control, having 8 2-axis analog sticks and 8 pushbuttons. Its brain is an ATMega8535 microcontroller (one of the oldest I have around), which reads the ADC values from the analog sticks and the digital inputs from the buttons, encodes the values into a data stream and sends it to the computer via a MAX232 level shifter and a HL-340 USB-serial adapter. The master application (on the master netbook) reads the values and forwards them via LAN/WLAN (using an UDP protocol) to the robot's computer. The robot's computer slave software reads the received data and computes the data stream that is sent to the robot. After I add some more sensors to the robot, the data read from them will be sent back to the master netbook. As you can see, the remote still needs a proper housing.

I also added a webcam mounted on a Dagu Pan/Tilt kit. Unfortunately, the micro sensors are not strong enough for the weight of the webcam (the kit was designed for sensors, so no wonder why). I'll either change the webcam with a smaller one (for the moment, this is the only I have around), or replace the servos with a pair of Futaba S3003 standard servos. Or both, as the webcam is large anyway and the servos lack precision.


So, for the moment the robot is able to be remotely controlled via WLAN, reads some encoder values and has a Sharp sensor that sweeps the area in front of the robot. The next steps would be sending all the information read by the robot back to the master computer (and use them in an useful way), add more sensors, improve the precision of the robot and develop a very user-friendly GUI for the master netbook (using, of course, the same SFML library and some of my old Photoshopping skills). Then maybe I'll have time to work on the exterior design (a housing for the robot and the remote). 

Comment viewing options

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

Cool project you've got there! Really like it.

Nice job on wiring the modules. Your boards seem to be cleaned up properly (no mess at least on the top of the boards). It's clearly visible that you've put some thought in each of the modules.

The battery voltage level display inspired me to do something like that for my robot. Could you explain the estimation/computing of the ADC-Values and the voltage divider a little more?


Keep up the good work!


Thank you for your feedback! The modules are, indeed, the result of a lot of failed or partly successful attempts, but still are quite messy underneath. I will probably replace, at some point, all the test circuit boards with printed circuit boards.

Now, the battery voltage display.

The voltage divider is made out of two 1K SMD resistors placed serially between the terminals of the battery pack. Therefore, on each resistor, there is a voltage drop equal to half of the battery pack's voltage drop. I connected a wire to the middle of the voltage divider (the point between the two resistors). This is the ADC input.

Z1 and Z2 are the two 1K resistors, Vin and the ground are connected to the battery pack (the ground is the same with the microcontroller's ground), while the Vout is the output that is read by the microcontroller via an ADC channel.

The ADC values have been computed using the voltage levels of the fully charged / fully discharged battery pack. When it's fully charged, each Ni-Mh cell has a voltage drop of about 1.4V, while the fully discharged level is at about 1V per cell. Discharging the cells to a voltage drop less than 1V/cell may damage them. Having 6 cells, this means that the package voltage drop is 8.4V when full and 6V when empty. This means that the measured voltage drop (accross the divider) is 4.2V when full and 3V when empty.

The reference voltage of the microcontroller is 5V (fed by the LM7805 voltage regulator), while the precision of the ADC is 10-bit. Therefore, the ADC extreme values are, roughly:

ADCmin = 1024 * 3 / 5 = 614; ADCmax = 1024 * 4.2 / 5 = 860;

Using these two values as reference values, I computed the intermediate ADC values by dividing the interval between ADCmax and ADCmin into 6 equal intervals. The device would have been more precise if I used the charge-to-voltage graphs of the batteries, because the output voltage is not a linear output of the charge level. The output voltage drops relatively quickly after a 10-15% discharge to a level of ~1.25-1.3 V / cell and remains quite constant until the cell is almost completely depleted. 

Of course, there was no need of the ATMega8 microcontroller. 8K of flash memory and 28 pins are a bit of an overkill for a simple battery level meter. I think an ATTiny26 (20-pin, 2K flash) would be more appropriate. In my case, the ATMega8 was the lousiest microcontroller ADC-capable that I had around. I will probably replace it with a cheaper ATTiny26 after I place my next electronic components order. Not to mention that I should have used some low-current SMD LEDs. Each of the 8 LEDs draws around 20 mA, meaning that around 100-150 mA are drawn constantly just by the battery meter. So there is a lot of room to improve it.

Hope I could help. 

You're using 1k resistors, isn't the current draw pretty high (about 4mA = 2 low current LED's) just for sensing purposes?

I actually didn't consider this. I used them because that's what I had around at the moment. I will probably rebuild this unit, using a smaller and cheaper microcontroller (the ATTiny26), some low-current LEDs and more appropriate resistors. I think 10k or 100k would be enough (400 or 40 uA sound better).

Oh, sweet. This project looks pretty cool.

I've had similar plans for modular control boards for a little while but have as yet failed to action them. I'd be interested to hear of any issues you've encountered or lessons you've learned from doing this.

Specifically I'd be interested on hearing how well your UART implementation works for the inter-board communication and how abstract the command sequences are (code would be good :D). By that I mean, you want to tell the robot to move forward so (i presume) the radio receiver decodes input from a remote controller and sends this as a command (Perhaps "1.0 axis1, 0.5 axis2") to the central controller and that sends some kind of message to the motor controller(s) (perhaps "0.5 left, 1.0 right")?

Also, have you encountered any issues with noise between the boards given the extra wiring?

The UART implementation is pretty simple: for each board, there are 1 or 2 data lines (if the board only has to receive OR send information or if it has do to both data send and receive), 1 interrupt pin and two power lines (VCC and GND). The protocol depends on what the board has to do. There are no address bytes or bits, because I assume quite without any risks that there are no package losses and that the bytes are received in the right order.

For example, for the motor controller module, it receives two bytes of data, one for the left engine and one for the right engine. The value of 128 corresponds to the neutral command, 0 represents the full backward command, while 255 the full forward command. Another example: the encoder board sends two bytes for the left encoder, two bytes for the right encoder and one byte stating the rotation direction of each encoder (CW / CCW). I could send other datatypes (16-bit, 32-bit variables) instead of bytes, but I find them easier to work with.

The radio module I used is a basic UART data transmitter/receiver pair. The remote control is actually a small computer application, using the SFML C++ library. It computes the appropriate values for the L and R motor channels and sends them via the USB remote, which contains an USB-UART converter, a MAX232 level shifter and the transmitter. The UART signal is sent at a baud rate of 4800 bps and received by the receiver connected directly to the main board.

The wireless protocol uses address bits in each byte of the package, so that each byte uniquely determines a particular command. The modules are quite cheap (about 10$ / pair), so there are some package losses even at distances of 10-20m. This is the reason I had to develop a protocol where each byte has address bits. I use 4 address bits and 4 data bits for each byte and the bytes that have a value between 0 and 32 are ommitted, because some of them represent special characters that conflict with the application. Therefore, I can control 7 8-bit channels after I decode the information. Actually, there are 2 8-bit channels representing the motor commands, 4 extra 8-bit channels for some other mechanical devices (I used them for a robotic arm at another project) and one 8-command digital (on/off) channel for controlling various auxilliary systems (i.e.: light, sound generator, etc.). The data is quite simple to encode/decode. If you want further details concerning the protocol, I'd be glad to explain them.

So far, I didn't have any noise issues concerning the wired data transmission. Nevertheless, if I use a baud rate higher than 57600, I sometimes have package losses even between two microcontrollers. That's why I chose the 57600 baud rate, it was the highest value that ensured, at least in my case, a lossless wired data transmission. I could have also used the I2C or SPI protocols, but I found them quite tricky to use and less customizable.

Hey Majik


This is a very neat looking bot.

I am interested in seeing your code for the Sharp IR sensor if you would be so kind as to post it. I use the same sensor but am not getting very good readings... I have found pages talking about linearising the output etc but am strugling to follow it. Of course, if you have code that solves the problem I would very much appreciate it if I could use it.


Well, I have the same issues you have. The values read by the ADC tend to oscillate a few units around an average value. For the moment, I haven't implemented any sort of filtering algorithm. I only approximate a mean value by reading 20 consecutive values and performing an arithmetic mean value. Something like this (BASCOM AVR example):

Dim Sensortotal as Long, Sensorval as Word, Sensorvoltage as Long, I as Byte

Sensortotal = 0

For I in 1 to 20 Step 1

    Sensorval = Getadc(0)

    Sensortotal = Sensortotal + Sensorval


Sensortotal = Sensortotal / 20

Sensorvoltage = Sensortotal * 5000 ' the sensor voltage will be expressed in mV

Sensorvoltage = Sensorvoltage / 1024

On the other hand, I can give you some tips that can be easily found in the sensor's datasheet and that improve signal stability and reading accuracy:

- first of all, notice the mounting position of the sensor on the servo; if it's placed vertically related to the plane of rotation, its reading are more accurate then if it's placed horizontally

- the manufacturers reccomend that you place a 10 uF capacitor between the VCC and GND pins of the sensor; this improves value stability

When I'll finally implement any proper filtering algorithm in order to process the input sensor data, I will post a brief explanation and some code snippets.

Hmm... thanks Majik (are you Polish?)

I was actually hoping for some code which converts the voltage into a distance.

Thanks for the tip regarding mounting it vertically. I will try that. Also, I need to source a JST connector - currently I have wires soldered to the sensor. Once I get the connector I will de-solder the wires and add capacitors as recomended.


No, I'm not Polish, I'm Romanian. The LMR nickname has nothing to do with my real name (David), it's just a virtual nickname I've chosen a long time ago for forum/website memberships.

On the other hand, I can help you with the voltage-distance conversion. I have written the code for a mini-radar that produces some computer graphical display and I used a conversion function there. If you're using the 10-80 cm sensor that I used, I already approximated the function needed to compute the distance (tell me if this is the case, I'll look for it in my code).

If not, I can tell you how to compute the function for a different range sensor. You need some graph plotting and fitting program (OpenOffice/LibreOffice Calc or Microsoft Excel would do fine). After that, place the sensor in a fixed position at least 2 meters away from any obstacles in that direction (let's say, on your kitchen floor). Place some paper on the floor and draw some points at fixed distances from the sensor (let's say, at each 5 cm). After that, connect your sensor to the board and just display the ADC value received from the sensor, so that you can observe what output the sensor produces when you place an object in front of it. Then, take a piece of white paper or cardboard and place it sequentially in all fixed points mentioned before and watch the sensor output values. For each distance of the fixed points you will be able to find an approximate value of the ADC output. Write down all these values as pairs (distance, ADC value).

After you collect the data, create a table with two columns: ADC value and distance (let's say, in cm). After that, plot a point graph using an appropriate computer program (as I said, OpenOffice/LibreOffice Calc or Microsoft Excel are good enough). After plotting the graph, you should insert a best-fit function, which represents a mathematical function of a particular type (exponential, polynomial, linear, logarithmic, etc.) that approximates in the best way the data you measured. This function, that the computer automatically finds, will give you exactly what you want: an approximate function f(ADC) = distance. It's not 100% precise, it has some intervals where it may induce some errors, but it's precise enough.

As I said, if you're using the 10-80 cm sensor, tell me and I'll look for the exact function. As far as I remember, it was something like distance = A * ADCvalue ^ B, where A and B were some constants. The function for the 20-150 cm sensor should look the same.