The overall architecture of the Sheldon robot is going to be modular. Aside from a central computer (probably a Raspberry Pi or some such), there will be multiple computers or microcontrollers each managing some sub-system. And the first of these is for motion control.
I decided on this hierarchical approach because of previous experience building robots. Most of these were controlled by Arduinos. And while they all worked, more or less, I always found I quickly got to the point where the Arduino’s main loop was getting overloaded.
What I mean by that is that there was too much polling of sensors and managing GPIO pins and whatnot. The robot became unresponsive because every time it needed to do one thing (such as notice that a proximity sensor had triggered) it was actually busy doing something else.
One way to overcome this is by the cunning use of interrupts – something I plan to use extensively. And the other approach is to offload some of the responsibility to separate modules, with the ability for them to talk to each other when necessary.
So, with the first module (or node) that I’m working on – a Teensy-based system that controls the motors – I’m also giving it the job of helping Sheldon not to bang into things.
The basic setup is the Teensy 3.5 and a motor controller board.
To this I’m going to add a number of sensors intended to provide collision detection and avoidance. The basic principle is that the core controller (the RPi) will instruct the motion controller to, ‘go forwards at normal speed until otherwise instructed’, or ‘turn right 90 degrees, stop and await further instructions’ or something else along those lines.
But it’s possible that, in carrying out these instructions, the robot will encounter a problem, such as an obstacle. Rather than bothering the core controller immediately, the motion controller node will have just enough intelligence to take appropriate action by itself. It will then alert the core controller as to what the problem was and what action was taken. The core controller can then accommodate that information into whatever cunning plan it has for the robot.
These semi-autonomous actions (‘semi-‘ because they’re limited in scope) will be things like:
- Slightly adjusting the robot’s direction if a rangefinder sees an obstacle in its path on one side only.
- Momentarily backing up and turning slightly before resuming motion if a proximity detector sees an obstacle close to the robot on one side only – eg, if the obstacle is on the left, the robot will back up slowly and turn slightly to the right before moving forward again.
- Stopping, backing up and turning 90 degrees if the robot hits something or if more than one of the front-facing proximity detectors fire. (Or possibly just stopping and waiting for further instructions.)
Each of these actions would be reported up to the core controller – possibly with some kind of priority rating – but to be held in a queue to be dealt with as and when appropriate.
So far, I have three infra-red proximity detectors waiting to be attached. These output a +5V signal that gets pulled to ground when an object comes within range. That kind of digital signal is perfect for using with interrupts, so there’s no need to poll the sensors during the Teensy’s main loop – just check for the state of a flag.
IR proximity sensors work reasonably well. But if you approach a flat surface at an angle, especially if the surface is shiny, the IR energy just gets bounced away from the sensor and it doesn’t trigger.
I’m also thinking of using ultrasonic and/or IR rangefinders. I’ve used these successfully before, although they can suffer the same problem. Typically, these either have an analogue output or they come with some kind of chip that provides an I2C or SPI interface.
For example, I have a Robot Electronics SRF10 ultrasonic rangefinder which has an I2C interface courtesy of an onboard PIC16F88 microcontroller. It’s very good, if a tad expensive. The problem is, you have to poll it. Every time through the main loop, you need to tell it to send out a ping, wait a moment and then report back the distance. In computer terms, this is quite time-consuming.
So, what I’m thinking is to, again, offload some of the work to a sub-system. You can get basic ultrasonic rangefinders for around $1.50. I could then control this with something like an AVR ATTINY84 which would be programmed to send out regular pulses and store the latest result. This microcontroller would also be attached to the Teensy – perhaps via SPI but also by an ‘alert’ connection. If the distance comes below a pre-set threshold, the microcontroller would take the alert line low, triggering an interrupt on the Teensy which would then interrogate the ATTINY for the actual distance.
Or perhaps not – maybe the alert is all that’s needed. But it might still be useful to have the SPI (or I2C) connection so that the Teensy could change the parameters of the rangefinder – setting a new alert distance, for example. It would become, effectively, a ‘smart’, programmable sensor.
Ideally, the Teensy would do almost nothing in the main loop except check for flags that have been set by interrupts and act accordingly.
The sensor of last resort in this plan will be microswitches attached to bumpers of some kind to detect if Sheldon has actually crashed into something. Again, these will be simple digital signals that will play nicely with interrupts. Building them will be the tough part – I’m not good with mechanical stuff.
And that’s as far as I’ve got. I think it’s a reasonable plan – now I just have to implement it.