Monday, April 29, 2013

Adventures in I2C

I've spent the last couple of days up to my armpits in I2C, so before it all evaporates I thought I'd better make some notes, and hopefully this helps someone else in the process.

In the last post I described having to grab some analog-ish data closer to the source, and I decided that I2C would be a good choice of bus because I can use smaller microcontrollers and two less pins. I'm not sure that's a good idea; it works, but I'm leaning towards going with AT328's all around, and sticking with SPI.

But for the time being, I'm going to give I2C a chance. I've used it before, from projects as small as an ATTiny 85 running an RGB LED, all the way up to LCD and LED displays, and it can work, so I know it's not a totally pointless exercise.

For background on I2C and the Atmel family, the best two sources - although somewhat conflicting - are these two pages: (the link starts towards the end of the page, but that's where the summary is - the whole page is a good read).

and an alternate library:

The second page, although it describes a fairly different set of commands than the Arduino documentation for Wire.h, does shine a light on the fact that Wire isn't so great, and how to use I2C as it was designed. I don't think Wire follows standards 'exactly'. Not that I2C has abundant standards, but that's another post... at least this alternate library does make the effort.

The interesting thing is how those two pages diverge in how they use I2C; the first link does have some goodness in it, but as the examples build, you end up with a somewhat non-standard protocol built on top of the I2C transport. That's not all bad, but it can mess with your head a bit in terms of interfacing at a more generic I2C level, and how to approach it in your own code.

The second link is more straightforward, and really shows what a vanilla-standard implementation should look like. The interesting thing is that the method of building a protocol on top of the transport is already assumed to be inherent in I2C; after all, there a zillion little I2C widgets out there already, and interfacing with them is usually a snap.

So what gives? What's the conceptual difference?


It all boils down to commands.

You don't need 'em - at least not as the first link describes them, and in fact if you try to make the examples in the first link talk to the examples in the second link - it won't work 'out of the box', because the implementers came at their solutions quite differently.

As an example, take a small analog-to-digital sensor of some sort, with an I2C interface to it. Pretty much all you have to do is wire it up, plug in the slave address from the datasheet into your Wire function calls, and start getting data, right?

You can even do things like change the I2C address in software (sometimes it's hardware jumpers, but for this example, assume it's software), or feed it a new calibration value that it uses in it's conversion math.

Those start to sound like commands... 'Change your I2C address to xxx, please!' or 'Set the calibration value to yyy right now!'.

Typically I2C devices are 'register based', so getting data or setting values is all about registers, which are most easily imagined as an array of bytes. Sometimes just one or two entries long; sometimes a dozen or more.

There is also the notion of reading and writing to an I2C device in the standard; partly by how you change the 7 bit address on the wire (with the LSB being the read/write bit), and partly by how it's implemented.

In the example device, you might read a calibration value from a register, so you know how the device is configured; or you could write to that register address with a new value, and change the calibration value.

And here is the magic. If it makes sense, the implementation should just take that value and also write it to EEPROM internally, so that the next time it's powered up, all the defaults are what they should be. You don't need an explicit command to write stuff to EEPROM - it just happens.

With that kind of conceptual model there is really no need for 'commands' at all - writing to registers ARE commands.

And if you really really want some extra flexibility, remember that a register entry, being a byte, can hold 255 different bit values... each one could be a different command. But if you are working with an 8k code limit in an 8 bit Atmel chip, I bet you run out of flash before you run out of command numbers to implement.

This register model is at the heart of the way that I'm building up the rover. Implementation-wise it's also a not-so-accidental fact that the register address label #defines can be stuffed into a header file and then shared between master and slave device. Nice and tidy.

But keeping the model 'pure', and NOT straying down the path of the first links example code has been a pain, since that's where I started, and expunging that has taken some time, but it's worth it. In the end I'll have a set of I2C slaves that will function with any master device, instead of a custom built master that layers on it's own protocols.

Sorry for not having any pretty pictures this time... perhaps next time I'll have some hardware moved off the breadboard to show for my coding efforts.

Saturday, April 27, 2013

Motor / Encoder Adventures

I finally got stable outputs from the encoders on the IG32's. It was nothing to do with the encoders, it was all interference picked up from the drive power lines. So that means a major re-design of the way I do motor performance measurement, since I need to do the ADC and encoder counting physically closer to the source, rather than back in the rover body. Dang it all.

That means a major re-wire, but it will be worth it. In the end I'll also have to run FOUR more Atmel MCU's; two ATTiny84's for the front wheels, and two AT328's for the mid-and rear wheels (one per side), and then tying this all together with a single AT328 as an I2C master. It does make a bit more sense and matches better with what I've done on the Rover 5 platform, which means the DRV chip is basically just handed an instruction to execute; ie "go that direction x units' or 'turn this much'.

The DRV chip then takes care of monitoring the progress and setting the PWM levels sent to the motor driver PCB's, so I can also bake in some anti-slip and anti-stall code fairly easily. I had to do this same idea on the Rover 5 to keep the tracks from coming off.

Anyway, below is the data from a set of tests on an IG32 motor. It's rated at 24v but run here at 25.2v (from a 6s LiPO battery), and being driven through a Cytron MD10C driver PCB. Actually, all three motors on one side were running for this test, although I only measured one of them.

The encoder outputs are pulled to +Vcc by a pair of 1K resistors (as per the datasheet), and then I watch just one of them in an interrupt. From that interrupt I also measure the other encoder, so I can deduce the direction, rather than use two interrupts per motor. This was an idea posted on the Arduino forums by user johnmchilton and it really makes more sense to do it this way.

The very small glitch around PWM = 187 is interesting; it's probably something to do with how the MD10C converts the input into an output, or how the Arduino / Atmel is doing it's PWM output - but I'm not going to worry about it at all.

The overall linearity of the system is really surprising; I was expecting more of an 'S' shape, with a slower build-up to a mostly-linear mid section, and then a tail off at the top where there would be essentially no difference between the to ~10% of the PWM values.

The top speed here is showing 205 cm/sec; or ~2 m/s, which is about 50x faster than Curiosity, which I think runs around 4cm/sec. Since this is a no-load test with the wheels were up in the air on that side, the real top speed can't be determined yet. I think the original design notes were for a 1.6 m/s top end, so it's likely I'll be in the right area. Given the way that the rocker-bogie behaves it's not like I'm going to be burning over rough terrain at walking speed anyway... for the rough sections it's easier to control at much slower speeds.

The speed is dictated by the wheel size and shaft RPM, which in this case are 120mm Wild Thumper wheels and the apparent RPM's from the encoder data was about 326 at PWM=255. That's faster than the rated 265 RPM; likely due to driving it at 25.2v on a fresh battery. I reversed the math to see if at ~24v it would be closer, but it still yields about 310 RPM.

My math could be 'off by one' here, as I was using 7 clicks per rev, as found by turning the wheel by hand and counting the encoders off. Each test gave ~133 clicks, which for a 19:1 gear train would be 7 encoders per rev. BUT I could be counting the start/stop click twice in my thinking, and it's really 6 encoder clicks per rev. That would actually mean it's faster, which again doesn't make sense. So maybe I'm not counting the last click (on average)... and it's really 152 clicks per rev (8 at the winding)... ahhhggg. It doesn't really matter, since the difference is only 10% in the speed, and I'm probably right; it's probably 7, because of the 19:1 ratio and the fact that all the tests gave around 133 to 135 clicks per rev.

Once it's on it's wheels again the way to get useful data will be to run some actual ground tests and measure the distances/times. I suspect I'll see more of that 'S' curve, where there will be a longer dead area at the bottom of the curve before wheel motion starts, and some top-end limiting, where it would be more efficient to run at 90% instead of 100%, and trade off a few mm/sec for a lot less current drain.

Sunday, April 14, 2013

Chassis Build

Ok, the parts mostly arrived, except for the few goofs I made during ordering. Below is a timelapse of the build, taken over a few evenings.

The liquid in the red bottle is (confusingly) 'blue' Loctite. The actual liquid is reddish. It's the 222 formula, which is about the limit for some of the small fasteners I'm using; if I'd used a more permanent formula it's possible that if I tried to loosen a screw it would just tear the head off.

The wheels are Dagu 'Wild Thumper' types, and the hub setback is totally opposite what I wanted and not reversable, which pushes the wheels out wider than the design called for. It's not fixable, but until I test out driving on a sideslope I'm not going to bother trying.

The hub to shaft adapters are Lynxmotion 6mm shaft to 12mm hex, which should really be 1/4" to 12mm hex. There is the smallest amount of play in them when mated to the IG32 motors.

The motor brackets are far too thin to work in this application, and after a week of sitting on them they started to deform. Because there were only 4 in stock when I placed the order I made two more out of brackets from Home Depot, and those don't bend. At least the pre-drilled ones gave me a good template to work from!

The fiddly bit in the middle spar is the differential that tries to keep the body level (or at half of each rocker/bogie angle). It's shown in the video as 3 gears, but really 4 is needed to keep gear backlash to a minimum. Here is a shot with 4 gears; I had to put a D-flat in a potentiometer shaft to support the 4th gear; I'd like to replace that with a pot that has a 1/2" shaft because it's getting in the way of the battery where it is now.

The motor controllers are Cytron MD10C's; they are rated up to 13A, and there are 4 of them. The front and rear wheels on each side share one controller, the middle wheel has it's own. The idea is that in certain turn-in-place moves I'd like the middle wheel to not drive (or drive as much) as the front and rear wheels, so I wanted to keep that control separate. The space at the front of the carrier plate is space for the wiring harnesses, and also for Pololu +/-30A current sensors, which I haven't bought yet.

... and where it sits in the back of the body, just in front of the fans. Those fans are 12v, so they are wired in series to the 24v supply. They aren't exactly what I had in mind in terms of airflow (37 cfm?) but until I test it under load to see what kind of heat the drivers generate I'm not too worried. They are also PWM capable, so I might add code to control that later.

 Here is a sample of the wiring harness for the 24v side; this takes power from the battery up to 2 panel switches, and ground out to a bus bar that goes out to the motor controllers and to the logic side.

At the front of the enclosure is a carrier for the brains; here it is incomplete; there is an Arduino Uno and a Chipkit Max32 on standoffs, and a PCB I haven't started building for the other three Atmel 328's. The standoffs aren't the same height so I can keep USB and power cables connected easily.

The Max32 (the big red one) is an 80Mhz 32 bit MCU, so it does the real 'thinking'. The Uno is an interface to the GPS Shield (an Adafruit GPS+logger), as well as the Magnetometer/Accelerometer via I2C, so it summarizes the position and orientation of the chassis. The 3 bare Atmel MCU's control and sense different things:

- one sends the drive signal PWM to the motor drivers, and does the encoder counting and temperature sensing

- one controls the steering PWM signals (to servos now, but may need an upgrade later) and reads 4 IR type sensors that look down in front of the corner wheels.

- and one controls the Pan/Tilt head and sensors.

I suppose I could have used a PWM breakout and fewer microcontrollers, but there is enough feedback in the system I'd need even more ADC to read the sensors. There are 8 temperature sensors, 2 voltage sensors, and possibly 6 current sensors,  plus a host of light sensors and indicator lighting, so the code would get very 'unmodular' in a hurry. This way I can change a bit of code on just one MCU and debug it a bit faster. It's complicated enough already, here is the layout of the MCU board:

Here is the back view, I don't have filters on the fans yet. The operator panel at the top has 3 main power switches, one for logic, and two for the left/right drive power distribution. This keeps the power per switch below the 20A rating. There are a bunch of LED's in and around the switches to inform the user when it's safe to turn things on and off. The round button is the run/stop switch, so the rover can sit powered on but not moving until told to. The RJ-45 jack basically feeds power and the I2C bus from the Max32 out to a hand controller that has some buttons and a 2 line LCD display (the Adafruit I2C RGB LCD).

In the video I said it was 18.5lbs, another checkup with most of the guts mounted (or in the body) shows I've hit 22lbs, so it's adding up quickly. I haven't checked my documentation and calculations yet, but I recollect being ok up to 26 lbs, which was notionally what the first Mars Pathfinder rover was.

The WCRS rules say 'no wireless', so I didn't add that yet, the hand controller interface is pretty much the only way to do on the fly calibration, short of pulling the microSD card out of the GPS logger and changing the config file on it.

I did buy a set of the cheap 2km 433Mhz TX/RX for debugging, but they are a gigantic fail. The reception is spotty and the speed is way to slow for anything but status signalling at something like 1 byte per second (4 bits per transfer at 0.5 seconds per send). I guess I'll have to go with my first instinct, and use Synapse boards.

One last thing - there is a cable draped across the top of the panel in that last image covered in that nylon sheathing used in PC cases... it's crap to use. It looks and feels fancy, but if you manipulate it more than once it starts to fray badly, since the ends need to be unfused to open up to slide the wiring in. Stay away!

That's it for now... hopefully by next weekend I'll have the first-drive done and some fun video and images to show for it!