Monthly Archives: December 2011

Telliskivi’s Brain: Overview

Now that we are done with the hardware details, let us move to the “brain” of the Telliskivi robot – the software, running on the smartphone. By now you can safely forget everything you read (if you did) about the hardware, and only keep in mind that Telliskivi is a two-wheeled robot with a coilgun and a ball sensor, that can communicate over Bluetooth.

You should also know that Telliskivi’s platform understands the following simple set of textual commands:

  • speeds <x> <y>   – sets the PID speed setpoints for the two motors. In particular, “speeds 0 0” means “stop moving”, “speeds 100 100” means “move forward at a maximum speed”, “speeds 10 -10” means “turn clockwise on the spot”,
  • charge – enables the charging of the coilgun capacitor,
  • shoot – shoots the coilgun,
  • discharge – gracefully discharges the coilgun capacitor,
  • sense – returns 1 if the ball is in the detector and 0 otherwise.
    (*Actually, things are just a tiny bit more complicated, but it is not important here).

We now add a smartphone to control this plaform. The phone will use its camera to observe the surroundings and will communicate with the platform telling it where to go and when to shoot in order to win at a Robotex Soccer game.

The software that helps Telliskivi to achieve this goal is structured as follows:

Telliskivi's brain
Telliskivi's brain

The Robot Controller

The Robot Controller is a module (a C++ class) which hides the details of Bluetooth communication (i.e. the bluez library and the socket API). The class has methods which correspond to the Bluetooth commands mentioned above, i.e. “speeds(a,b)“, “charge()“, “shoot()” and “sense()” and “discharge()“. In this way the rest of the system does not have to know anything at all how exactly the robot is controlled.

For example, a simple change in this class lets us use the same software to control a Lego NXT platform instead of Telliskivi. That platform does not have a coilgun nor a ball sensor (hence the shoot(), sense() and discard() methods do not do anything), but it can move in the same way, so if we let our soccer software run with the NXT robot, the robot still manages to imitate playing soccer – it would approach balls and desperately try to push them towards the goal. Looks funny and makes you wonder whether it is polite to laugh at physically disabled robots.

Obviously, the robot controller is the first thing we implemented. We did it even before we had Telliskivi available (we could use the Lego NXT prototype at that time).

Graphical User Interface (GUI)

The GUI is the visual interface of the smartphone app. Ours is written in QML, a HTML-like language for describing user-interfaces. Together with the Qt framework this is the recommended way of making user applications for Nokia N9. It takes time to get used to, but once you grasp it, it is fairly straightforward.

The overall concept of our UI is not worth delving deeply into – it is just a bunch of screens organized in a hierarchical manner. Most screens are meant for debugging – checking whether the Bluetooth connection works, whether the robot controller acts appropriately, whether the vision system detects objects correctly, and whether the various behaviours are behaving as expected.

In addition, there is one “main competition” screen with a large “run” button, that invokes the Robotex soccer mode and two “remote control” screens. One allows to use the phone as a remote control for the Telliskivi platform and steer it by tilting the phone (this is fun!). Another screen is meant to be used as a VNC server (so that you can log in to the robot remotely over the network from you computer, view the camera image and drive around – even more fun). For the curious, here are some screenshots:

Telliskivi smartphone app UI screenshots
Telliskivi smartphone app UI screenshots
Telliskivi smartphone app UI screenshots
Telliskivi smartphone app UI screenshots

Vision Processing

The vision processing sybsystem is responsible for grabbing the frames from the camera (using QtMultimedia), and extracting all the necessary visual information – detecting balls, goals and walls. In our case, parts of the vision subsystem were also responsible for tracking the robot’s position relative to the field. Thus, it is a fairly complex module with multiple parts and we shall cover those in more detail in later posts.

Vision module
Vision processing

Behaviour Control

The last part is responsible for processing vision information, making decisions based on it, and converting them into actual movement commands for the robot – we call it the “behaviour controller”.

As the camera was the main sensor for our robot, we had the behaviour controller synchronized with the camera frame events. That is, the behaviour controller’s main method, (called “tick”), was invoked on each camera frame (which means, approximately 30 times per second). This method would examine the new information from the vision subsystem and act in correspondence to its current “goal”, perhaps changing the goal for the next tick if necessary. This can be written down schematically as the following algorithm:

on every camera frame do {
   visionProcessor.processFrame();
   currentGoal = behave(currentGoal, visionProcessor, robotController);
}

In a later post we shall see how depending on the choice of representation of the “goal”, this generic approach can result in behaviours ranging from a simple memoryless single-reflex robot, to somewhat more complex state machines up to the more sophisticated solutions, suitable for the actual soccer-playing algorithm.

The ROS Alternative

As you might guess, all of our robot’s software was written by us from scratch. This is a consequence of us being new to the platform, the platform being new to the world (there is not too much robotics-related software pre-packaged for N9 out there yet), and the desire to learn and invent on our own. However, it does not mean that everyone has to write things from scratch every time. Of course, there is some good robotics software out there to be reused. Perhaps the most popular system that is worth knowing about is ROS (“Robot OS”).

Despite the name, ROS is not an operating system. It is a set of linux programs and libraries, providing a framework for easy development of robot “brains”. It has a number of useful ready-made modules and lets you add your own easily. There are modules for sensor access, visualization, basic image processing, localization and control for some of the popular robotic platforms. In addition, ROS provides a well-designed system for establishing asynchronous communications between the various modules: each module can run in a separate process and publish events in a “topic”, to which other modules may dynamically “subscribe”.

Note that such an asynchronous system is different from the simpler Telliskivi approach. As you could hopefully understand from the descriptions above, in the Telliskivi solution, the various parts are fairly strictly structured. They all run in a single process, and operate in a mostly synchronized fashion. That is, every camera frame triggers the behaviour module, which, in turn, invokes the vision processing and sends commands to the robot controller. The next frame will trigger the same procedure again, etc. This makes the whole system fairly easy to understand, develop and debug.

For robots that are more complicated than Telliskivi in their set of sensors and behaviours, such a solution might not always be appropriate. Firstly, different sensors might supply their data at different rates. Secondly, having several CPU cores requires you to run the code in multiple parallel processes if you want to make good use of your computing power. Even for a simpler robot, using ROS may be very convenient. In fact, several Robotex teams did use it quite successfully.

In any case, though, independently of whether the robot’s modules communicate in a synchronous or asynchronous mode, whether they are parts of a framework like ROS or simple custom-made C++ classes, whether they run on a laptop or a smartphone, the overall structure of a typical soccer robot’s brain will still be the one shown above. It will consist of the Vision Processor, the Behaviour Processor, the Robot Controller and the GUI.

Summary

To provide the final high-level overview, the diagram below depicts all of the programming that we had to do for the Telliskivi project. This comprises:

  • about 800 lines of C code for AVR microcontrollers,
  • about 7000 lines of C++ code for the Vision/Behaviour code
  • about 2000 lines of QML code for the smartphone UI elements.
  • about 900 lines of Python code for the simulator
  • about 500 lines of C++ code for the Vision test application (for the Desktop)
Telliskivi software
Telliskivi software

Robot’s hardware: Summary

By now we have completed the series of posts describing the “hardware” of our robot. Here is what we have covered.

If there is anything regarding the hardware of the robot that should be explained in more detail – feel free to ask in the comments.

The Budget

To finalize the story of our hardware development, let me show you the budget, i.e. the money we spent on building the robot in the table below. There are two numbers for each expense. The “nominal price” denotes the approximate minimum amount of money one should expect to spend on a particular item. The “we paid” price denotes the actual amount we had to pay. It is nearly always different from the nominal price for two reasons:

  • In some things, such as the smartphone and CNC manufacturing we got help from the sponsors (Nokia, Tööstusplast, Tartu University Institute of Technology and the Robotics club of the University of Tartu). Thus, we spent less than the nominal price.
  • For other things, we spent more either because we bought back-up items (you never know when something is going to burn so this is always a good idea) or because we did not know exactly which particular option we would need and had to try different options.

I might have forgotten or left out something, but the table below should give a reasonable impression of a minimal expense sheet for a robot like Telliskivi. The prices are in euros.

Item Nominal price We paid Remarks
Electronics (275.00 | 325.73)
Miscellaneous (55.00 | 37.28)
Sockets, pinheaders, buttons, etc 15 18.18
LiPo 3-cell battery 30 0 Provided by the Robotics club
Battery voltage converter circuit 10 19.10
Main PCB & motors (140.00 | 217.70)
Main (motor control) PCB 35 0 Provided by the Robotics club
Motor drivers 30 45.80
Motors 60 122.20 We ordered two pairs, just in case
Wheels, wheel mounting hubs, motor mounting brackets 15 49.70 In the end we did not use the wheels nor the motor brackets. We did need two sets of wheel tires and mounting hubs.
Coilgun (50.00 | 39.60)
Coilgun PCB 35 0 Provided by the Robotics club
Capacitor with mount 5 9.60 We bought two, just in case
Coilgun wire 10 30.00 We tried several options
Bluetooth module (30.00 | 31.15)
BlueSMIRF Silver 30 31.15
Mechanics (130.00 | 114.34)
Nuts and bolts, spacers, rubber bands, springs, ball bearings, grease, … 30 92.52
Sheet plastic and CNC cutting 50 14.07 Tööstusplast sponsored most of the manufacturing. The “nominal price” is an optimistic guess.
Sheet aluminium and laser cutting 50 7.75 Metec sponsored most of the manufacturing. The “nominal price” is an optimistic guess. The “we paid” price includes the price for restoring a lathe and a drill broken by us.
Other (0.00 | 105.51)
Postage and taxes on stuff ordered from Pololu and Proto-pic 0 105.51
Total: 405 545.58
+ Nokia N9 600 0 Provided by Nokia
Grand Total: 1005 545.58

Let me summarize this to those of you not interested in detailed numbers.

  • If you are willing to make a similar robot, be prepared to spend at least 400 euros. Out of those, you will spend about 100 on raw materials and manufacturing, 100 on microcontrollers and PCBs, 100 on “large” components (motors, capacitors, battery) and 100 on all kinds of nuts, bolts, connectors and wires. If you plan to order stuff from abroad, prepare another 100 for shipping and taxes.
  • You might easily end up spending at least twice the nominal amount on some articles either for experimenting or for safeguarding against failures on the last moment. This can double your numbers up to 1000 euros.

If you now include expenses on junkfood, transport and the sleepless nights spent by the four team members making and programming the robot, you’ll see that participation in Robotex is, in fact, a very expensive project (for a student, at least). But it’s worth it none the less!

Bluetooth

OK, so we have made the chassis with a couple of motors, a coilgun, a ball detector, and the electronic circuitry to control all of this. This makes up the “body” of our robot and what remains is the “brain”. As you should know already, the brain in our case is a Nokia smartphone. The brain needs to be constantly communicating with the body – sending movement and shooting commands and reading ball sensor and perhaps motor sensor data. As we explained in one of the first posts, we need to use the Bluetooth protocol for such communication.

We thus had to purchase a separate module and connect it to our main microcontroller (attentive readers have already seen this module in one of the pictures). There is a fairly wide variety of Bluetooth modules available out there. Our criteria for choosing a suitable one were the following:

  • The module must have an integrated implementation of the full Bluetooth protocol stack. Bluetooth is a fairly complicated set of protocols, and there are some modules which only implement parts of it. The remaining parts would have to be implemented in software (i.e. in the microcontroller) and this would make our life difficult.
  • The module must use the UART protocol. This is the default serial protocol supported by our microcontroller. Most Bluetooth modules use it anyway.
  • The module must have a readable datasheet. Debugging a no-name module with no reference manual is not something we look for.
  • The module should be reasonably priced. Although ELFA is certainly not a place to look for “reasonably priced” things, we can use the knowledge that the cheapest module there (which happens to fit the previous criteria) costs €32.50.
  • Finally, the module might have some positive reviews on the internet.
BlueSMIRF Silver
BlueSMIRF Silver

SparkFun’s BlueSMIRF Silver happened to fit all of them (especially the last one), so we ordered it and so far it has been one of the less troublesome parts of our robot. Although it does have a detailed datasheet, pretty much none of that information was even needed, because the module does most of the work itself. All the microcontroller has to do is read and write bytes over the UART pins, to which the module is attached.

To read and write over UART we borrowed the code from the Teensy UART library and added a couple of simple wrappers around the low-level uart_getchar and uart_putchar methods. After this was done, we could complete the main loop of our robot’s microcontroller:

int main() {
    // ... initialization code ...

    char buf[32];

    while (true) {
        bool success = recv_command(buf, sizeof(buf));
        if (success) execute_command(buf);
    }
}

This function, together with the interrupt handlers mentioned in the post about motor control, is essentially all there is to our main microcontroller’s code.

Serial Communication and Interrupts

If you will be implementing a similar solution, beware of one particular hidden reef. The UART communication in Atmega uses interrupts to receive bytes. That is, every time a new byte arrives on the serial port, an interrupt handler is invoked. The code in this interrupt takes responsibility of storing the received byte into a buffer for further processing. While this interrupt is in process, no other interrupts will be invoked. For example, if during the reading of a byte a motor encoder happens to send a pulse, this pulse would not get counted, simply because the controller won’t be there waiting to catch it.

This issue is even worse the other way around – if the microcontroller happens to stay “too long” in one of the other interrupts, he might simply miss an incoming byte. As a result, weird things will start happening – the command “move” might get received as “mve” or worse still, a command separator character will be missed and two commands will be concatenated into one.

There is really no good solution to this problem besides being careful and not writing code which might stay too long in an interrupt handler. At one moment we had an interrupt handler like that (the one which performed the PID computation in a timer), and it resulted in a fairly large number of communication errors. Surprisingly, the problem nearly disappeared after we rewrote the computation from 32-bit integers to 16-bit integers. It turns out that an 8-bit microcontroller can spend too much time simply adding and multiplying 32-bit numbers.

Bluetooth and Latency

A final word of warning is related to latency. Although the communication speed for a Bluetooth connection is quite good (in our case it was actually limited by the UART’s 115 kbps), the latency is not. That is, although you might easily send up to 15 000 single-character commands per second on a UART+Bluetooth connection, if you require (and wait for) a response to each command, the actual throughput can be somewhere around 30-60 commands per second.

In fact, this particular problem (and the fact that we discovered it too late to go fixing) has been one of the main reasons why our robot was somewhat “slow” during aiming in the final competition. We focused a lot on keeping the vision processing speed at 30 frames per second as this was, according to general knowledge, the hardest part to get working fast. Unknowingly, we were at the same time unreasonably wasteful in communication. Whenever robot would have the ball in the dribbler, we would query the ball sensor too often. As we would also wait for sensor query command to respond before proceeding with computation, this (rather than the dreaded vision processing!), was the reason our actual processing speed went down to about 15-20 fps every time the robot was holding the ball. Those were, however, exactly the moments when the robot was aiming for the goal and needed as high a framerate as possible.

Operating the Coilgun

Now that we’ve figured out how to operate a motor, let us describe the second important electro-mechanical component of the robot – the coilgun. Previously, we have already discussed briefly the general idea and its mechanical realization. What remains are the minor implementation details.

Recollect that the general scheme of a coilgun (somewhat simplified, of course) is the following:

Coilgun
Coilgun

In order to make this scheme operable, we must replace the switches “Enable charge” and “Enable discharge” with transistors, connected to a microcontroller. In our case we had a separate microcontroller operating the coilgun, which means that we also needed to establish communication between the main controller and the coilgun controller. The resulting scheme is then, in principle, the following:

Coilgun control
Coilgun control

The task of the coilgun microcontroller is rather simple: receive signals from the main microcontroller and set its output pins A and B accordingly. Our robot’s coilgun controller implemented essentially the following four functions:

void enableCharge() {
    set_pin(PIN_A, 1); // Enable charging of the capacitor
}

void disableCharge() {
    set_pin(PIN_A, 0); // Disable charging of the capacitor
}

void kick() {
    set_pin(PIN_B, 1); // Start discharging capacitor
    delay_ms(5);       // Wait 5ms
    set_pin(PIN_B, 0); // Stop discharge
}

void dischargeSlowly() {
    for (int i = 0; i < 20; i++) {
       set_pin(PIN_B, 1);
       delay_ms(1);       // Discharge a bit
       set_pin(PIN_B, 0); // Let the kicker be pulled back
       delay_ms(5);
    }
}

The last function (dischargeSlowly) is there to allow a graceful shutdown of the robot, where the capacitor discharges without the kicker having to jerk hard.

The communication between the main microcontroller and the coilgun may be implemented using various protocols. Originally, our coilgun PCB was meant to be controlled via the SPI protocol, but during one of the mishaps the corresponding pins burned down and we ended up using a simpler solution, where three output pins of the main controller were directly connected to the input pins of the coilgun board. A command was sent by specifying its code using the first two pins and sending a pulse on the third one.

If you will ever be making your own coilgun…

It must be noted that the coilgun was perhaps the most complicated electromechanical part of our robot and as this blog tries to make things sound as simple as possible, it sweeps some details under the carpet. If you, dear reader, for some reason, will be going to build a coilgun yourself (perhaps when taking part in one of the next Robotex/Robocups), take your time to skim through the following sites first:

Safety notes

In order for the coilgun to be capable of hitting the ball with appropriate force, it must contain a reasonably large capacitor, and large capacitors can be dangerous. A 1.5mF capacitor, when charged to 250V, stores 0.0015·250² = 93.75 Joules of energy – something comparable to an energy of a 10kg brick falling from 1 meter’s height. If such a capacitor short-circuits, all this energy can get released in a single explosion, and you do not want your fingers to be nearby. Even if your fingers are spared, your electronics can get irreparably damaged.

In order to avoid a capacitor explosion (there were at least three of those among the Tartu teams during the two months leading to Robotex), keep in mind the following:

  • You should not short-circuit a capacitor. Obviusly, this will result in an immediate discharge of all its energy, which means an explosion. Of course, no one ever short-circuits a capacitor deliberately, but it is unexpectedly easy to do it accidentally.
  • You should never physically damage a capacitor. A damaged capacitor may short-circuit internally and explode for no apparent reason later on. Hence, if a capacitor falls on concrete floor once, beware when reusing it.
  • A capacitor must be used with appropriate voltages and connected in accordance to its polarity. Invalid voltage or polarity may damage it internally, which will lead to internal short-circuit.

To be more specific, here are some educational stories:

  • Some guys were debugging their PCB using a digital oscilloscope and touched a “positive” end of the capacitor with a “ground” probe of the oscilloscope. As a result, there was a short circuit through the ground, boom.
  • Other guys were trying to fix something using a screwdriver right on a working robot with a charged capacitor. Screwdriver touches the metal cover of the robot (which most probably was connected to the “ground”. of the electronics somewhere). Next, either due to a static discharge from the screwdriver, or due to its external potential acting to inversely polarize the capacitor, the boom happens.
    In fact, touching a working robot with a metal object is a bad idea for many more reasons. The two times when our team has managed to mess up the electronics were both related to someone trying to touch a working robot with a metal object. So beware.
  • Yet other guys have attached a capacitor to their robot using just Velcro tape. The robot starts spinning, the tape does not hold, the capacitor slips off and touches some of the electronics with its terminals. No boom, but all of the electronics burned down.

 

Operating a Motor

After we have chosen the motors and motor drivers, we must connect them to a microcontroller and control their rotation. How do we do that?

The Microcontroller

In our particular case we used a microcontroller chip mounted on a custom-printed circuit board together with the motor drivers, which we ended up not using anyway. Thus, our life would have actually been easier if, instead of using that custom board, we would just buy some well-known pre-made microcontroller board. The popular choices included Arduino, Teensy, Baby Orangutan, Basic STAMP, ARM mbed, TI LaunchPad, ST Discovery, and anything else you might google up using the keyword “microcontroller development board“. Hence, for simplicity, I shall avoid details specific to our case and assume the set-up with such a separate board.

For those of you not familiar with microcontrollers, it is enough to understand that a microcontroller is a just a black-box chip with several pins (those are the metal “legs” of the chip).The microcontroller can be programmed to set output voltage on some of the pins to certain values (usually either 0V, corresponding to “bit zero” or 5V, corresponding to “bit one”). It is also possible to sense input voltage on some other pins. Those two basic operations allow the microcontroller to communicate with other devices connected to it.

So, we have to connect some output pins of the microcontroller to the motor driver. Then, by setting appropriate output voltages on those pins, we shall be telling the motor driver to operate the motor as necessary. How exactly should the motor driver chip be connected and operated is specific to each chip, but in principle the assembly for one motor might look as follows:

Motor connection
Motor connection

Controlling the Motor

In the example above (which corresponds to the driver we used), two pins (A and B) are used to tell the driver in which direction to rotate the motor. The whole code for specifying rotation direction is thus as simple as:

if (rotate_forward) {
    set_pin(PIN_A, 1);
    set_pin(PIN_B, 0);
}
else {
    set_pin(PIN_A, 0);
    set_pin(PIN_B, 1);
}

Specifying rotation speed is just a bit trickier. For that we must produce a pulse width modulation (PWM) signal on pin X. This simply means quickly switching pin’s values between 0 and 1, so that on average the value “1” is kept a given fraction of time. A “full PWM” would mean keeping pin X at “1” all the time – in this case the motors would rotate with  their maximum speed. A “null-PWM” means keeping “0” all the time. This corresponds to motors not rotating. All values inbetween are also possible. If pin X is at value 1 one third of a time, the motors will rotate with approximately a third of their maximum speed.

PWM with 1/3 duty cycle
PWM with 1/3 duty cycle

Most microcontrollers have built-in mechanisms for producing such a signal on some of the pins. We won’t delve into details of doing that – there are lots of tutorials out there already. For all practical purposes, the actual code for setting the motor speed boils down to

set_pwm_pin(PIN_X, speed); // speed = 0..255

Feedback

Are we done? No. Unfortunately, simply setting the motor rotation speed to a fixed number is not enough for precise control. For example, if we set the PWM speed inputs for both robot motors to the same value, despite all expectations, the robot will most probably not drive perfectly straight. Thus, to ensure exact control, we must constantly measure the actual rotation speed of the motor and adjust the PWM to keep the speed at a given value.

In order to measure motor rotation speed, our motor is equipped with a rotary encoder: a sensor, which generates pulses in accordance with the rotation. The faster the rotation – the more pulses are generated per second. To obtain this feedback information we first connect the motor encoder to an input pin of a microcontroller:

Motor with feedback
Motor with feedback

Next, we write a simple function that simply counts all pulses that come in on pin E:

ISR(INT0_vect) {
    pulse_count++;
}

Finally, we set up a timer interrupt that will regularly examine the current pulse_count value, compare it with some target value, and adaptively update the PWM signal on Pin X so that the target rotation speed is achieved:

ISR(TIMER0_COMPA_vect) {
    current_pulse_count = pulse_count;
    pulse_count = 0; // Reset pulse counter

    // Update pulse counter
    update_motor_speed(target_pulse_count, current_pulse_count);
}

PID controller

So how do we use the feedback and choose the appropriate PWM value to set for the motor speed in order to keep up with the target pulse count? This simple question has a whole discipline dedicated to answer it, known as control theory. The easiest answer that control theory provides us here is the PID controller.

The idea of a PID controller is generic and simple: we first measure the discrepancy between the target pulse count and the actual measured pulse count (the error):

error = (target_pulse_count - current_pulse_count);

In addition, we keep track of the error, accumulated over multiple iterations of the algorithm, and the difference between the error of the previous iteration and this iteration:

error_i = error_i + error;
error_d = error - prev_error;

The actual input to the motor driver is now computed as a linear combination of these three error values with some experimentally determined coefficients P, I and D:

new_pwm = P*error + I*error_i + D*error_d;

If the parameters are chosen well, the PID controller will magically keep the motor turning at the necessary speed.

So, to summarize the above, the update_motor_speed function may look approximately as follows:

void update_motor_speed(int target, int current) {
    error = (target - current);
    error_i = error_i + error;
    // Prevent the integral term from growing too large
    if (error_i > max_error_i) error_i = max_error_i;
    if (error_i < min_error_i) error_i = min_error_i;
    error_d = error - prev_error;
    prev_error = error;
    new_pwm = P*error + I*error_i + D*error_d;
    set_pwm_pin(PIN_X, new_pwm);
}

Our actual function was somewhat more complicated and included a couple of specific hacks and improvements, but the gist is still there.

Summary

To summarize, here is what you need to do to properly operate a motor:

  • Connect the microcontroller’s output pins to a motor driver, and the motor driver to a motor.
  • Use pins “A” and “B” (or whatever the motor driver specification requires) to set motor rotation direction.
  • Connect the motor’s rotary encoder sensor to an input pin “E” of a microcontroller.
  • Make sure the microcontroller is counting the pulses on pin “E”.
  • Set up a timer, that reads the counted pulses and updates the PWM parameters on pin “X” to match the “target_pulse_count“.

The same logic applies for the second motor.

But where do the motor direction and values of target_pulse_count come from? Those are specified by the higher logic, running in the phone, of course. We’ll get to that eventually.

 

The Motors

The parts of the robot, that have turned out to be one of the trickiest for us, were the motors. There are three motors in our robot – two for the wheels and one for the dribbler, and all of them have been causing headaches.

Choosing the Motors

The variety of motors one can choose for the wheels of a robot is staggering. How to choose the right one? Here’s how we went about it.

The first decision we had to make is whether to use a brushless vs brushed motor. The former type is typically more powerful, more expensive, and requires somewhat more experience to operate. The latter type is what most would call a “usual” motor. Having no prior experience with brushless motors and no desire to spend extra money, we went with the simpler option.

Next, we have to pick a particular motor. Two main functional characteristics play a role here:

  • Motor rotation speed – this will specify the max speed at which the robot will be capable of moving.
  • Motor torque – this will define the acceleration the robot will be capable of achieving.

The theory goes approximately as follows. Start by finding the necessary rotation speed. We know that the diameter of the wheels of our robot is 6cm. We would like the robot to be capable of moving at a maximum speed of about 1 m/s. That means, the motor must be capable of rotating with speed 1 / 0.06π ≈  5.3 revolutions per second, i.e. about 320 rpm. If we give it a little slack, we might be looking for a motor with free rotation speed of about 350-450rpm.

Next, let us compute the torque. Ideally, we might be willing for our robot to be capable of accelerating to the speed of 1m/s in about half a second, i.e. the maximum acceleration for the robot must be about 2m/s². The weight of our robot, fully assembled, is about 3kg, hence the motors will need to provide a force (F=ma) of at least 3·2 = 6 Newtons. In particular, 3 Newtons is the contribution that we expect from each motor. We also have to account for friction, and here we just blindly say we need about twice the force, i.e. 6 N from each motor. If our wheels would have a radius of 1 meter, we would need a motor with a torque of exactly 6 N·m to achieve that. Our wheels have a radius of 3cm, however, hence we would like a motor with a torque of about 6·0.03 = 0.18 N·m. Depending on the manufacturer, the motor may either be specified in terms of “rated torque” – this is a constant torque the motor is capable of providing for long periods of time, or “stall torque” – this is the maximum torque the motor provides when stalled. The stall torque is typically at least twice the rated torque, hence, according to our computations above, we might want a motor with a rated torque about 0.2 N·m or a stall torque at least 0.4 N·m.

Pololu motor
Pololu motor

After having scouted the web from end to end, we ended up ordering a pair of these and a pair of these motors from Pololu. Besides fitting our specification, the motors have a reasonable size (some alternatives were inconveniently large to fit into the robot) and have a rotary encoder built-in, which is a feature worth paying a couple of extra euros for. Pololu also sells useful accessories, such as wheels and wheel attachment hubs, which we also ordered. It turned out the attachment hubs we chose were not suitable for the 6cm Pololu wheels, though, so we ended up lathing our own wheels but still using the tires.

The Motor Driver Problem

The important feature of a motor is its stall current. This is the current that the motor consumes when stalled, i.e. exerting maximum torque. This happens when the motor is just about to start rotating, when someone prevents the motor from rotating freely (e.g., the robot has bumped into a wall) or when the robot is trying to accelerate. The motors we ordered have their stall current specified at 5A. However, the motor drivers we had to use on our motor control PCB (designed last year for Tartu’s last year’s robots), were only meant for 2.8A or smaller currents. (In case you already forgot, this post explains what is a motor driver). “Ah well, let’s just try and see what happens, maybe the drivers will just burn down”, we thought, and we tried. Unfortunately for us, the drivers did not burn down.

They kind-of worked, but worked badly. In order to run the motors at smaller speeds we had to use weird hacks, which are not worth delving into here, and in the end, the motors still wouldn’t behave predictably. After about a month of suffering and making us come up with ugly hacks, the drivers did finally burn down, and it was good. Because by that time we have already ordered a new, more powerful pair of drivers, and needed that final push to have those installed. As soon as we got the normal drivers set up, motors started working as necessary, and life became beautiful again.

Burned drivers
Burned drivers

The picture below shows the lower side of our motor control PCB. The three empty spots are the places where the three original motor drivers have been (the board was originally designed to accomodate four drivers, to be used with four-wheeled robots). One of the drivers burned down when we touched a working robot with a screwdriver (separate story). Two other ones burned for some reason later. The last driver is still sitting there, and it was used to control the dribbler motor, but eventually it also burned.

The moral of this story is simple: if you use powerful motors, use powerful motor drivers.

The Dribbler Motor Problem

As mentioned above, we were using the remaining driver to control the dribbler motor (so that it would be possible to choose the speed at which it would be rotating). However, we had bad luck with this one too. Despite the fact that the dribbler motor was not trying to consume too much current, the driver for it managed to burn down three times for no clear reason (some local gurus suspect that the motor was too “low-quality” for the driver, in the sense that its brushes produced too much spark discharges when switching). So in the end, we got tired of replacing the driver over and over and had the dribbler motor connected directly to the battery via a button. It was a very good choice and I am sorry we didn’t make it in the very beginning. So let me leave you another suggestion, dear reader: if you have a choice between a simple button and a complicated electronic microchip (such as a motor driver) strongly prefer the former!

The last remark is in order. Some of the Tartu’s other teams tried using brushless motors for the dribbler (simply because those were available), but as far as I’ve seen this has caused them way more trouble than it was worth. So if you, dear reader, plan on making a soccer robot, do not use a brushless motor for the dribbler. Just take any generic reasonably-sized brushed motor that you will find lying around in the lab, connect it with a button, and that’s it, you’re done. Tartu team Sidi had it done this way and, it seems, did not have any problem with their dribbler at all.

Once the motors are connected and running, we must somehow control them from the microcontroller. We’ll leave it as a topic of a later post.

Robotex 2011

So, the last three weeks were full of hectic preparations to what culminated in this weekend’s Robotex competition. Our team was incredibly lucky and did just great, winning the fourth place out of 16 participants, beaten only by the three teams from IT College. Considering that the IT College guys have been polishing their three more-or-less similarly designed robots for three consecutive years under the careful supervision of an experienced leader, we do not feel a single bit disappointed to grant them the fair victory. Telliskivi fought its best, losing to the overall winner with a close score of just 5:6.

The main factor which gave the ITC robots a defining advantage was their superiority in speed. This is not something unsurpassable – there were just technical reasons why Telliskivi was tuned to a “slower” setting for the competition, and we’ll discuss this in a later post, now that we finally have time to go on describing the ins and outs of our robot.

We are waiting for the Robotex organizers to put the competition videos out on their web – those are really fun to watch. So far, let me just share a couple of my own shots.

The competition-ready robot

Just a day before Robotex, on Friday, we received the final cuts for the transparent plastic cover of our robot.

Telliskivi, Friday, Nov 23rd.
Telliskivi, Friday, Nov 23rd.

On Saturday, we also found out that the horizontal bar on the goals will be attached firmly, so we added a couple of “frames” to preserve the phone in case the robot decides to drive into the goal (which we now could afford to allow in the algorithm).

Telliskivi, competition-ready
Telliskivi, competition-ready

Nights before Robotex

Robotex is known for its promise of sleepless nights, and that promise was fulfilled. In fact, the bulk of the most important code was actually written during the last two nights. Something tells me it is not just our team who had it this way. Here’s how the competitor’s area looked at 3AM on the night before competition. Things didn’t change much all the way through to 8AM – there were still people working hard on the last-moment fixes.

Telliskivi’s first round
The only round I managed to get on my camera was our first game. It was easy to win – the opponent was extravagant, but non-aggressive. The opponent’s name was “Ventikas”, it was made by kids from the Kullo hobby club, and the sly trick it relied upon was to be large, stand at its own goal and blow air in three directions diverting the balls away from the goal. Unfortunately, the fan was not strong enough, otherwise it might turn out to be an unexpectedly hard opponent to beat. Note the careful aiming Telliskivi is making to get the ball exactly into the goal – at this point the judge asked me to stop filming as he suspected we might be remote-controlling it. That’s what good AI is all about – it looks like a human is behind it.

Telliskivi on TV

On the day before Robotex we actually got to show off our robot briefly on the early morning show on the national TV. Footage here (starting at 1:11:40).