Thursday, December 19, 2013

I2C, PCB's and other TLA's

TLA's. Three Letter Acronyms. Not only are there too many out there already, I have invent some of my own...

If you recollect, the rover chassis is a six wheeled, rocker-bogie type of autonomous platform. It's about 25 lbs, so it's not exactly a toy. Steering turned out to be impossible for the cheap hobby servos I chose, which were only rated for something like 89 oz-in of torque. I needed something with more go-go juice, and as it happened I had several identical gear motors that looked the part. What they lacked was any kind of motor driver and feedback loop, like a traditional servo.

Enter the L293D, a smallish and cheap driver chip, and the Atmel ATtiny 84, a smallish and cheap micro controller, and some kind of feedback potentiometer. Oh, and a circuit board... which led to a need for creating and ordering PCB's. I sketched out what would end up being a multifunctional module referred to as a 'STR84', which does a few jobs:

  • Temperature sensing of the motor from a TMP36 (really just a simple ADC conversion to I2C register storage, plus I2C based tuning).
  • Reading a quadrature encoder in the motor and calculating rate and direction
  • Driving the L293D to steer left and right based on I2C commands
  • Getting feedback on steering angle from a simple potentiometer
  • Controlling a servo on which is mounted an IR range sensor
  • Getting the range data from the IR sensor via and ADC.

I had several other boards to create, so I got to work.

After some fiddling in Fritzing I had enough information to get some quotes on having the PCB's fabbed... er... or not. I think it would have been more than $500, considering all the different boards I had planned, but more on that later. After gathering the materials I found I could get great results with presensitized boards and so-so results with the magazine toner transfer method. I use two fluorescent lamps to expose; one grow lamp and one backlight, and I use HCl + H2O2  as the etchant. That's another whole story...

A comparative image of a standard sized hobby servo and the gear motor. The actual motor core is easily several times larger, and it's 24V, where the servo is 6V. The completed driver PCB is on the left.

The hobby servo has an aluminum horn on it, which has the laser from the last test still mounted on it.

Here is a finished steering controller board, and three more waiting for drilling and parts. I did the first one just to be sure it all worked, and that it was worth finishing the rest of them.

This is a front/back mirrored shot, which might be a bit easier to relate component locations on. The reason for the different colours of screw terminals is to remind me which is input power (the black one) and which is for the motor (the green one).

But I didn't start with the mid-sized boards I needed for the steering servo, I decided to start with it's smaller brother, the two boards for the two middle wheels. These don't drive any steering motors, but have identical functionality for sensing the temperature of the drive motor via TMP36's, and counting it's encoder pulses from sensors in the motors. I called them 'TE85's", as they are built around the Atmel ATtiny 85, which is one of the smallest / coolest / cutest little 8 pin micro controllers out there, so they generally run the same code, including communications.

A family picture: below is the bigger STR84 steering controller, and the smaller TE85, which only does encoder counting and temperature. On the AT85 the I2C signals and power enter on the 4 pin connector, and the 6 pin header is where the encoder and TMP36 connect. Really the only thing going on here is a power LED (surface mount, on the back) and two 1K pull-ups for the encoders to work. There is a cap on the AT85, and it looks like I haven't drilled out the mounting holes yet!

On the larger board the I2C and power is on the 6 pin connector on the upper right. The 4 and 6 pin connectors share the same layout (Vcc, Gnd, SDA, SCL) on the first 4 pins, and the extra two pins of the 6 pin connector are for servo power and ground. This common pin layout means that any 4 pin module can plug into any 6 pin bus header, and the two servo power pins don't have to connect to anything.

Some thoughts on I2C:

Most of the communication on the rover is via I2C, for about a hundred reasons...

- it only takes 2 pins. SPI takes 4 on the receiver, and a gazillion on the master (ok, one per slave, or you can mess around with shift registers. No really, YOU can mess around with shift registers, I'm saving the parts count and headache...)

- it has a small memory footprint.

- only very small amounts of data need to be moved

- TinyWire rocks. It's super stable. It's like Wire.h on Arduino, but for the ATTiny chips.

- I2C allows for a little slack in the timing. Did I mention it just works really well?

- it has separate read and write modes, so fewer accidental screw ups.

- uniquely addressed slaves, and enough address space for my purposes (all this stuff is 7 bit addressing).

How many modules, you ask? Lots; these plus the 'cape' type connector for the Beagle Bone and the voltage regulator boards adds up to about 16 or 17 PCB's. Not all are I2C enabled; maybe next time!

  • Four steering controllers on the four corner wheels.
  • Two temperature/encoder controllers on the middle wheels
  • One front end for a 16 channel ADC MUX board
  • One user control panel controller
  • Two IR range sensors and the associated pan servos
  • A high mounted status RGB LED (this was built before Neopixels existed)
  • A bigger microcontroller for the Pan/Tilt sensor head (a '328).

And the 'store-bought' modules:

  • One Magnetometer / Accelerometer
  • One 16 channel PWM driver

That's 14 modules, if I didn't forget any.

 There are fewer modules that aren't I2C:

  • JPEG camera - via UART
  • GPS - via UART
  • Ultrasonic Rangefinder - via UART (I suppose I could make an I2C front end for this, but it seems like overkill...)

That's it. I might add an SPI LCD display for onboard status... but not yet.

Back to I2C, I cleaned up the standard code I use, and added a few administrative functions:

  • A 'system clock' that ticks independently of I2C, but can be read / cleared to confirm a module is running
  • A heartbeat counter that only increments/clears when commanded. I may add some watchdog functionality here so it can put a module in safe mode if a watchdog command isn't heard in a given time.
  • EEPROM writing and loading, as well as warm-booting.
  • A standard layout of registers for status and commanding
  • Parameter register locations that are read and used elsewhere in code as variables
  • A simplified command methodology, where a single CMD register is written to with the command identifier. Most (or all) the needed parameters should already be loaded in other register locations.
That's it for now. I have some PCB drilling' to get to!

Tuesday, December 17, 2013

Lasers and Servos!

So you've mounted a sensor on a servo and are happily gathering data as your sensor sweeps back and forth.

Where is your sensor looking?

For some obstacle avoidance tasks it doesn't matter much. If the sensor detects something 'close' and has a field of view in the direction of travel, that might be all you need.

But what if you need to do some trigonometry with the sensor angle to determine actual range or elevation?

Probably then you'll want to move the servo a bit, wait for the servo to move, and then take a reading.

How long to wait? Based on published specs, you might do some math like 60 degrees in 0.18 seconds is 3ms per degree, and call it a day.

Or, you could strap a laser to the servo and actually measure it.

I did this experiment by mounting a small $5 laser on top of the servo and turning it on for 1ms at the measurement points, and set my camera to a 1.5 second exposure. That way I can see the entire sweep, and where the laser spots are really pointed. The angles used are chosen that they fall at equidistant points on a flat surface when the servo is mounted to the rover. Here, at the incorrect angle, it's still obvious that timing is everything.

Watch below as the delay between moves is decreased; the measurement position becomes more incorrect because the servo can't keep up. The start position is on the right, and the furthest travel is on the left. See how the dots start to shift to the right?

I'll need to refine the tuning code so I can adjust the delay per movement once it's mounted in the right orientation and position on the rover. That way I can ensure that the delay is correct, and that my chosen angles actually fall at evenly spaced points on the ground in front of the rover. Stay tuned!