czech english


quarter-finalist of Eurobot 2003

Daisy was an alternative robot prepared for the contest Eurobot 2003. Daisy was significantly simpler than its sister Dana and again it turned out to be the most critical point. Daisy ranked at the 7th place which is quite an achievement for such a well known international competition.


Daisy was based on the triangular chassis from the previous robot Berta. The same motors with 20:1 gearboxes were used. Also the encoders from PC mouse were the same. The control board was replaced with a simpler version based on a microcontroller AVR AT90S8535, which worked very well already for our old robot Alena. The main advantages of this chip are its price, availability and freely available software tools. The main computer was iPAQ, a pocket PC with WinCE operating system. The flipping mechanism, dual-cannon and all the other mechanical parts were created from Merkur (Czech version of Mechano). Finally four servos handled motion of the various mechanisms.


Top view
Top view
The basic triangle was the same as for the robot Berta. This triangle was extended by a construction from Merkur. The contest rules limited robot perimeter (or better its convex projection onto a plane) to 120cm. The triangle already ate 90cm so there was not much space left for experimentation. Finally the rhomb shape was used as it yielded the widest possible robot.
The core of the flipping mechanism was an L-shaped hand with two degrees of freedom. It could either flip the puck or let it go based on its color. The main advantage of this solution was that the robot did not have to back up or even stop when manipulating the pucks. The task was then simplified to just finding some pucks. The L-hand was quite fragile, so we built a cage around it for protection. Another reason for this cage was bringing down pucks in the vertical position, and guiding them directly into the hand.
From the left side (this robot had the front given by the pointy end of the triangle) there was also a small protection barrier against stacking pucks. Finally this construction also protected sensor Sharp GP2D12 mounted in the middle of the robot, scanning its left side.
A small holder for the pocket PC became another reinforcement of the robot frame. It was mounted on the required beacon support. A week before the contest a double-cannon mechanism was build. It could fire ping-pong balls against single-colored pucks. The cannon could easily shoot 5-10m, and was triggered in two steps with a single servo.

Control hardware

Electronics from the back
Electronics from the back
The robot's electronic brain was created by several separate modules. The main board was based on a microcontroller AVR AT90S8535. This chip with 8kB programmable flash memory, 512B SRAM and 512B EEPROM, can run on 8MHz. There are eight 10bit resolution A/D converters, three timers, two PWM channels, and 32 digital I/O pins. The chip is easy to program via parallel port. Yes, the price is also nice - around 200Kc, which is approximately 7EURO .
The main board provides almost all available pins. Some of them are connected through a resistor to an LED indicator, others to a comparator with a trimmer. Everything is connected using jumpers, so it is easy to disconnect the LED or the comparator. There are six digital outputs forming tri-connectors <ground, external +5V, I/O pin>, for easy plugging of the servos. The analog inputs form a similar configuration <ground, +5V, analog in>, so many external devices or sensors can be directly plugged by a simple tri-connector.
The main board contains a socket for an H-bridge L293D. If more powerful motors are needed, as in the case of Daisy, then an external H-bridge can be connected.
Many smal board were added later on. There was one board with MAX232 for a serial communication with PC, various filters for the Sharp sensors, a board for encoders (it was actually the original board from Berta), and a board for handling light gates.


At the beginning Daisy had only a few of CNY70s for detection of black and white color. Two of them were build into the L-hand for puck color recognition. The first sensor pointed up and the second one down, so simple difference of analog values allowed a very reliable classification (all two-colored pucks were from inside half black and half white). The other X CNY70s (originally 3, then 5 and at the end 4) were used for a navigation based on the color of the floor.
The second type of sensors were two Sharp GP2D12 with a maximum range around 80cm (minimal about 8cm). An extra filter was need for 1kHz noise (the sensor signal was modulated with 1kHz and it also influenced the analog output). In the final configuration one Sharp was mounted in the middle of the robot pointing left, used for mapping of pucks, and the second was mounted just below the beacon support for detection of the enemy robot (or better its beacon).
From the big set of digital inputs only two were used - one for the starting cable and second for a light gate of a puck detector. There was also a second light gate detecting pucks entering the Merkur construction and one micro-switch for a collision detection, but both were disabled in the final code.


The “brain” of Daisy was iPAQ, a pocket PC with WinCE operating system. This computer talked to the main board via serial line (a communication speed was set to 36400baud). All decisions were made by the iPAQ only. This configuration turned out to be very good. It was possible to write a program directly in C++ and compile it on a standard PC or laptop. It was easy to debug and modify various settings. When the program was finally stable enough, you could just swap the cables and re-compile the same program for iPAQ. In 98% the program run immediately without any need for a change.
There were couple differences which made our lives harder:
  1. the compiler for iPAQ did not support templates and exceptions in C++
  2. you will get different results for iPAQ if you use floats instead of doubles, while our laptop internally always computed in doubles
  3. our program for iPAQ did not support text output on the screen
  4. iPAQ runs on 200MHz, which is less than ordinary PC, and mathematical operations with floating point are implemented with a software emulation


The main board

The program for the main board was written in C. We used proved technique of access to all low level variables. Daisy had following outputs from iPAQ: PWM for the left and right motors, positions of four servos, watch dog, digital outputs. The inputs were: timer, encoders status, digital inputs, analog inputs. All communication was block oriented. The main board was always slave and the iPAQ master. Each block was protected with an extra checksum. The main board had only one task - directly realize commands from the master. There was one exception: if the time given by the watch dog elapsed turn both motors off. This feature was very useful for the moments when a cable was disconnected or the program was waiting on a forgotten breakpoint.

Simulation, reality, log…

Software for the iPAQ was “slightly” more complex. It grew bottom-up, so the very first thing that was implemented was an encapsulation of the communication with the main board. This was handled by a class AbstractHardware, which had exactly the same parameters as the structure sent over the serial line. It had only one extra pure virtual function synchronize. It probably does not have any sense to go into more detail, so let's rather talk about what it was good for: this solution allowed very simple switching inputs and outputs of the whole program. It could be direct communication with the AVR chip or it could be a simple simulator or a binary log file. The program would not recognize it.
I consider this trinity: simulation, real run and run from log file, to be such a critical point, that I decided to dedicate a whole paragraph to it. Why? Ok, when you are at the very beginning, you usually have nothing or nothing working. It is necessary to make sure, that the mistake is not in the software, so you just test it with a simulator first. I am not talking about any complex software package costing several thousands dollars. I mean just two lines of code, which for given PWM generate output on encoders in given direction. That's it. If you want something better then you can for example compute robot position, and draw it on the screen, but it is not necessary. And if your control program sends some non-senses you can debug it with simple stepping through the code.
When your program works fine with a simulation you can let it run in reality. It should not happen any more, that your robot will start in the opposite direction than you expected and that it will badly hurt itself in the collision with the radiator. If so, then you should probably fix the simulator and the cycle repeats. It is a good idea to check that the robot really received the commands you sent. This is the reason to use log-files. Generate them always and generate their name automatically. Only this way you will not loose previous, maybe important, log. Also happend just now in reality may not repeat next x months… until it happens at the very worst moment – believe Murphy .
End of the lecture – this was the core of Daisy we could build on. I would say that Daisy belongs to category RobotXP, where this trinity is similar to unit tests in eXtreme Programming. And what was it all good for?
Robot strangely limped loosing its position almost one square, but then somehow corrected the error.
The log showed that the analog input number 7 connected to CNY70 for the floor color detection was always 255. One pin of the sensor was broken and it needed a replacement. This happened just two hours before departure for the Istrobot competition.
Daisy behaved so well that I decided to make a demo for a friend of mine. He pulled the starting cable and the robot started to twist and hit both sides of the playing field many many times. During 90 seconds the robot did not leave initial four squares so its score would be 0.
The log looked ok, but the program using the data from log file (here I would stress that it is very critical that the program running from log must behave exactly the same, i.e. for the same inputs it has to generate the same outputs, otherwise it is completely useless – it is also a good idea to check this detail and be careful with random generators, float vs. double arithmetics, timers etc.) immediately after the start positioned the robot at negative coordinates outside the playing field. The error was in the initialization and emerged only if you waited long enough before you trigger the starting cable and in the first 50ms you pushed the robot a little. This bug did not show up for several months, but with the log file it took just a couple seconds to find it. Can you imagine looking for it without the log? I can't.
Robot started, but during the whole match it did not turn a single puck although the light gate detected them (LED indicates interruption of the beam). Is the power regulator fried or did we mess up the code for the main board when we extended it from two to four servos?
The log showed … that the problem is in the software so it is not necessary to check cables and connections. Simply, servos did not receive a command to move. Why? A bad initialization again - this time in the module for handling pucks. Usually I ran hardware check program before the main application, but I did not do it this time. So there was a huge number in the variable m_lastTimeCmdChanged and the module could not change the hand position until this time has elapsed.
Is it enough or should I add a few more experiences with the Sharp sensors, which see pucks at any distance depending how you look at them…?

Strategy & modules

When the essentials work everything is much simpler. If not then it is necessary to simplify everything and it may start to work. This is probably our global strategy but I did not plan to talk much about this one now. An example could be a task to follow a path. Daisy moved nicely but slightly in curves. We tried various types of controllers but in the sharp turns it always panicked a little and did not correct the error in time before the next turn. Solution? We decided to use the same controller as Dana. Shortly, Daisy moved straight only, and when it wanted to turn, it stopped and turned in place and then continued straight again. There were much less parameters to tune and worked in short time quite well…
Another software package directly used from Dana was GMCL (Genetic Monte Carlo Localization), a module for navigation using CNY70 and known ground color. If the robot moved without collisions then this method kept its position within +/- 5cm and approximately 10 degrees of angular error. This was enough for the puck collection but as we found out later it was insufficient for precise shooting.
The puck flipping and the navigation worked independently. Module Flipper checked only if a puck is present, and if so then, based on its color, it flipped or let it go. There had to be a short pause between each command, approximately 1-1.5 sec so that the servos manage to move to the required positions. This worked quite well if the robot moved forward but it sometimes failed when turning right or backing up. This concept was not changed/improved for the contest.
The motion planning evolved from fixed path to a map integration and shooting balls. The final version which was used for all matches on Eurobot 2003 used this program:
SeqEle seq[] = 
  SeqEle(SeqEle::GO_TO_WAYPOINT, 0.45, 0.45),
  SeqEle(SeqEle::GO_TO_WAYPOINT, 2.4, 0.45),
  SeqEle(SeqEle::GO_TO_WAYPOINT, 0.3, 0.6),

  SeqEle(SeqEle::GO_TO_WAYPOINT, 0.3, 1.05),
  SeqEle(SeqEle::GO_TO_WAYPOINT, 2.4, 1.05),
  SeqEle(SeqEle::GO_TO_WAYPOINT, 0.3, 1.05),

  SeqEle(SeqEle::GO_TO_WAYPOINT, 0.3, 1.65),
  SeqEle(SeqEle::GO_TO_WAYPOINT, 2.4, 1.65),
  SeqEle(SeqEle::GO_TO_WAYPOINT, 0.3, 1.65),

  SeqEle(SeqEle::GO_TO_WAYPOINT, 0.9, 1.65),
  SeqEle(SeqEle::GO_TO_WAYPOINT, 0.9, 0.45),
  SeqEle(SeqEle::GO_TO_WAYPOINT, 0.9, 1.65),

  SeqEle(SeqEle::GO_TO_WAYPOINT, 1.5, 1.65),
  SeqEle(SeqEle::GO_TO_WAYPOINT, 1.5, 0.45),
  SeqEle(SeqEle::GO_TO_WAYPOINT, 1.5, 1.65),

  SeqEle(SeqEle::GO_TO_WAYPOINT, 2.1, 1.65),
  SeqEle(SeqEle::GO_TO_WAYPOINT, 2.1, 0.45),
  SeqEle(SeqEle::GO_TO_WAYPOINT, 2.1, 1.65),

  SeqEle(SeqEle::GO_TO_WAYPOINT, 2.7, 1.65),
  SeqEle(SeqEle::GO_TO_WAYPOINT, 2.7, 0.45),
  SeqEle(SeqEle::GO_TO_WAYPOINT, 2.7, 1.65),
The robot was supposed to move from the starting position (the bottom left corner had coordinates 0.0 0.0) and to move parallel to the long sides of the field. Concurrently the mapper scanned all pucks on the left side within 60cm. The command ASK_MAP then produced a list of new goals so that Daisy started collecting all pucks on the left side. Most of the pucks were dropped but they no longer were in their initial positions.
After cleaning of the first two rows Daisy moved to third row, reset its map (RESET_MAP) and repeated the same maneuver. Similarly it handled the fifth and sixth row. This pattern was then repeated in the perpendicular direction, parallel to the shorter sides.

Collision detection

The strategy just described also integrated collision detection. If the upper Sharp sensor saw the second robot in the way to the current goal position (WAYPOINT) it switched to the next one in the table. Similar steps were performed when the collision was detected from the virtual bumper.
The dual coverage of the field in two different directions (in the time limit 90 seconds Daisy could not do much more) had an advantage that if the second robot got stuck somewhere Daisy finished unclean part in the second direction.

Weaknesses and problems

Detection of the enemy robot definitely did not work for 100%. It would be necessary to remember at least the last scan, because the upper servo scanned the environment only once a second. The main reason we did not implemented anything more sophisticated was, besides lack of time, bad experience with the fixed Sharp for mapping the pucks positions. It turned out to be critical for the mapping to scan the whole scene and then look for a global minima. It was impossible to decide from a single measurement if the puck is in distance 60cm or 25cm (moved from the axis of the sensor beam). We expected very similar problems and in France there was no spare time for a sufficient testing and analysis.
Another weak point was a recovery from localization failure. If a heavy and strong robot hit Daisy then GMCL typically lost the track, and the pre-planned path could not be realized. This for example happened in the last match with Supaero, when after the collision Daisy just remained in one corner hitting the field boundary. It would be necessary to detect this situation, and start to move without the knowledge of the position or self-localize again. We had an idea for relatively simple algorithm: if the lower Sharp sensor does not see any obstacle but it should see the side of the game area then the robot is lost. It worked relatively ok, but we did not test it sufficiently and we did not have any strategy without knowledge of position ready, so we did not use it at the end.


Daisy was another robot from category RobotXP (this is my term, so do not try to look it up in an encyclopedia ), which with a plenty of luck managed to reach its potential life top. Daisy is also one of the robots you can build yourself so we hope it can be also a small motivation for you… .

If you have any questions or comments – let us know.