More robot software improvements
The Abington firefighting competition is one month away. I’ve been working hard on the controller software, and at this point FireCheetah reliably navigates on continuous surfaces (floor or rug). That is well ahead of where things were last year! Along the way I came across a few things that may be useful to other roboticists.
A better ping library for ultrasonic sensors
There are quite a few Arduino libraries out there for ultrasonic sensors. They are important for this robot, as a key loop involves driving forward until we are a certain distance away from a wall. Ultrasonic sensors work via echo-response, sending out a ping and waiting to see how long it takes to come back. Usually that happens fairly quickly, but if there are no obstacles within the range of the sensor, the code will keep listening until it times out. It turns out that the library I was using before had a fixed timeout value of one second(!), from the Arduino function pulseIn. One does not want a robot running a full second without any feedback. Pretty poor library design, as pulseIn allows you to customize the timeout value.
I stumbled across a far better library, NewPing. The home page lists its advantages:
- Works with many different ultrasonic sensor models: SR04, SRF05, SRF06, DYP-ME007 & Parallax PING)))™.
- Option to interface with all but the SRF06 sensor using only one Arduino pin.
- Doesn’t lag for a full second if no ping echo is received like all other ultrasonic libraries.
- Ping sensors consistently and reliably at up to 30 times per second.
- Timer interrupt method for event-driven sketches.
- Built-in digital filter method ping_median() for easy error correction.
- Uses port registers when accessing pins for faster execution and smaller code size.
- Allows setting of a maximum distance where pings beyond that distance are read as no ping “clear”.
- Ease of using multiple sensors (example sketch that pings 15 sensors).
- More accurate distance calculation (cm, inches & microseconds).
- Doesn’t use pulseIn, which is slow and gives incorrect results with some ultrasonic sensor models.
- Actively developed with features being added and bugs/issues addressed.
I immediately implemented the setting of a maximum distance, and the lag time went away.
The author had some impressive thoughts on why one should avoid using delay() in code.
Simple example “hello world” sketches work fine using delays. But, once you try to do a complex project, using delays will often result in a project that just doesn’t do what you want. Consider controlling a motorized robot with remote control that balances and using ping sensors to avoid collisions. Any delay at all, probably even 1 ms, would cause the balancing to fail and therefore your project would never work. In other words, it’s a good idea to start not using delays at all, or you’re going to have a really hard time getting your project off the ground (literally with the balancing robot example).
The NewPing library offers an event-driven mode, which I might try, though it is arguably more than I need and complexity runs the risk of adding bugs. The thinking here did inspire me to get rid of delays in all my PID loops — which get called over and over again from different pieces of code. Instead they do a check to see if sufficient time has elapsed before resampling and correcting. I have to think that once one goes down the road of balancing ball robots (which I’d love to do one day) a multi-threaded operating system is the way to go.
Of course, with all this, the biggest improvement I made with the sensors was discovering and fixing a bug from last year’s code: I had incorrectly used a tangent instead of sine. Now the wall alignment works every time.
Upgrading the Arduino avr-gcc compiler
When compiling my project over and over again in Eclipse, I always saw a strange warning: “only initialized variables can be placed into program memory area”. This was a little disturbing and eventually I decided to track it down. Turns out that the avr-gcc that ships with Arduino 1.0.3 is not the latest version, and it has bugs. Although I could have lived with the warning. I decided to upgrade after reading this post about the buginess of old avr-gcc with Arduino Megas. I had experienced the difficulties with global constructors that the author mentions. And so, I followed his directions to upgrade to avr-gcc 4.7.0 and avr-libc 1.8.0. I did not upgrade the Arduino IDE as I had a newer version than he did, but I did have to add
#define __AVR_LIBC_DEPRECATED_ENABLE__
to HardwareSerial.cpp so that it would compile correctly.
As I’ve mentioned before, developing on microcontrollers is not for the faint of heart. I don’t think I’ve ever had to upgrade a compiler in all my years of commercial software development. Ugh.
Carpet obstacles
The carpets in the competition are a challenge, as hitting one at a key point can cause the robot to lose track of odometry. This year I bought some carpet samples in the hopes of doing more realistic testing. As discussed on my previous post I redid the drive train with no gearboxes and the wheel base moved to the rear. Things are looking very stable. I am not ready to declare 100% success yet. It is particularly challenging to go from a polished floor onto a raised carpet. The Abingdon maze last year had flat rubber/carpet flooring, so much easier with the extra traction, but I don’t want to take any chances. Much more testing is required.
Once again software improvements are key. I now assume the carpet will toss the robot around and it may lose sight of the wall temporarily, but it is smart enough now to look around for a while with its sensors before giving up. As long as the robot can mount onto the carpet successfully, all’s well. Right now the left wheel is having trouble doing this from a smooth floor; that motor is slightly loose due to a missing retaining ring so I will replace it and see it what happens.