We spend a big chunk of last weekend trying to track down an issue with our motor driving logic. The problem was that sometimes a fast change of direction would cause the i2c bus to die; writes from the Pi would fail and the bot would go crazy as result.
We knew it was likely to be one of a couple of factors:
High current draw from the quick change in direction causing a brownout.
Motor switching causing interference/voltage spikes.
Unfortunately, not owning an oscilloscope, it was hard to pinpoint the exact cause so we resorted to magic capacitive pixie dust and software changes:
We added large reservoir capacitors to the power inputs of the various boards to provide a store of charge in case the power rail momentarily dropped.
We added small decoupling capacitors too to help filter any noise.
Those changes did seem to help but they didn’t eliminate the problem completely. An extra layer of software changes seems to have done the trick:
We changed the i2c driver code to close and reopen the device file after a failure. The hope is that that resets the bus more thoroughly than simply retrying the write.
After John mentioned that he’d seen issues with it in the past, we took control of the GPIO pin that is attached to the propeller’s reset pin and started actively driving it rather than letting it be weakly pulled up with a resistor.
We beefed up our retry loop, with escalation. If it fails enough times, it resets the propeller and reflashes it. That takes about a second but it might just save us on the day!
We implemented a maximum ramp rate for the motors so that we change their speed a little slower.
We put the motor PWMs out-of-phase so that they don’t all start and stop on the same clock cycle.
With all those changes in place, we’ve seen a few retries but it’s hasn’t escalated to a reset yet so, fingers crossed, the problem is fixed enough.
So two of the PiWars 2018 events suggest using servos to operate something: duck-shoot and golf.
Servos have been around for a long time and have a very simple interface. About every 20ms, you need to send them a pulse. That pulse needs to be between 1ms and 2ms long. A pulse length of 1.5ms will cause the servo to move to the centre position, 1ms and 2ms correspond to the two ends of travel. Note that some servos can move beyond these limits, and some can be damaged if you drive them beyond these limits! If you fail to send a pulse every 20ms, the servo will power down (stop actively driving the motor to a particular position).
See https://www.raspberrypi.org/forums/viewtopic.php?t=46771 for more details and Pi driven solutions.
In Tigerbot, our servos are driven by the Propeller Hat. This is a microcontroller with 8 cores. It takes some of the load off the Pi and because it isn’t running an operating system, it is possible to *guarantee* pulse timings. Our controlling Pi then sends desired servo positions over to the Propeller using I2C, then the Propeller sends servo pulses. Here’s a demo:
Last year we ran with ultrasonic ping sensors, but a lot of the teams were using the VL53L0X time of flight sensors with good results. So this year we thought we’d have a go with some of those too. We got the ones on a pololu carrier board for about 10 quid each.
And they’re *lovely*. I think that under the covers they’re doing something very complicated/interesting and hiding all that from us, but the readings we get from them are very accurate and very consistent. No need for any averaging or filtering code on the Pi side.
Its not all roses though. The minor downside of that complexity is that you need to initialise them with a C-library. If you’re using the python library, that’s all taken care of for you, but we are writing our code in Golang, so we had to mess about linking in that C-library.
Another quirk to be aware of – they are an I2C device, so they all need an I2C address. They come with a fixed one from the factory. If you only have one this is fine, but if you have more than one, they will all have the same address… Other I2C sensors usually allow you to tune the address with jumpers, but this doesn’t seem to be an option with these boards – at startup you need to hold all but one in reset (using GPIO pins) and then send it I2C commands to change the address, and repeat with a different one in reset. We decided we didn’t have enough GPIO pins for this.
Alternatively, you can use an I2C multiplexer like the TCA9548A (adafruit do a nice carrier board for it too). With this, you attach the ToF sensors to the different buses coming out of the multiplexer, then you send commands to the multiplexer to change which bus you want to talk to.
Here’s Tigerbot wearing a few sensors on its front.
At the centre of the robot’s performance is the motors and motor drivers. We’ve tried many options over the years: old drill motors (cheap and powerful, no position feedback), stepper motors (very controllable, heavy, expensive), brushed DC motors with gearboxes and encoders (fairly powerful, fairly expensive, good position feedback).
We’ve considered (but not yet chosen) brushless DC motors (most powerful for their size, controllers very expensive).
This year (like last year) we went with brushed DC motors with gearbox and encoders. Last year’s units came from China via ebay which caused us trouble when a gear cracked at the last moment and we were unable to get a replacement in time. This year I decided that all our critical parts were going to come from suppliers in Europe, and be a brand name so that they could be easily purchased from multiple suppliers.
We went with Pololu gear motors – 25mm diameter units with gearboxes. These motors come in a range of power/gearing options with the same form factor and we could buy them from both RobotShop and TME. The motor drivers were the same as last year: 13A Cytron units from Robotshop. These should be able to deliver twice as much current as the motors can handle.
Here’s the populated chassis. Motor drivers are on the left, Pi + propeller + interconnect board are on the right. Space for a LiPo battery is at the front. And right at the bottom is a little 5V switch-mode power supply (as used in model aircraft) to power the logic boards.
At the heart of the robot is the Pi. But how does it connect to everything else? Via the interconnect board of course 🙂
This little board is where *everything* connects – where all the sensors, motor drivers, power supplies, Pi, Propeller, etc come together. Its a very custom board for every robot, so I generally make it by hand using “padboard”. This is a cheap, 0.1 inch pitch board with drilled pads. Unlike stripboard, it doesn’t have defined tracks – so you make your own with solder bridges.
This allows a more compact layout than stripboard, while still being fairly quick/easy to use.
Our board has headers on it for logic power supply (in the middle), motor drivers (6 pins, near the edges), sonar pingers (blue) and servos (yellow).