Saturday, May 11, 2013

WCRS 2013 in photos

What a fantastic day for an outdoor robot race, for the 2013 Robot Games! It made for some great images, and there were a few fun surprises, too. So this post is a little heavy on the pictures, and they will be slightly larger-than-normal images for today.

Although one of my many hats is as a professional photographer, I brought my big-boy camera along today because I wanted to do a little 'intelligence gathering' on the off-roadbot course. But I punched up the images to '11' and slapped a Creative Commons license on them, primarily so the folks who run the games can lift the images and use them however they want.

Why on earth would a professional photographer do such a thing? Give away images? "Because I can, and because it's worth it." Read the rest of the post to figure out why. It's really the most important reason these games exist.

I was a little late to check out the action indoors, but I did get to see the quadcopter demo outside. Here is the quad, hovering to the left of the tent. The idea is to fly a pattern through the hoops in the tent and land on the garbage can, but it was too gusty. I think I could build something for this next year... hmm...


Next I turned my attention to the off-road course. It looks pretty easy, until you try to walk on it. It's not flat. It's not smooth. It's a storm water drainage holding area, so it really doesn't get mowed, either. It's perfect!


Here it is with the hazard cones placed. The starting line is between the two furthest cones, and the goal is to get back to near where I'm standing and through the fence gate, which means climbing the low slope out of the drainage area and motoring down a gravel road.


There is also a really good reason the area is fenced off. The aerospace museum is at the end of the runway, in one of the commercial parks that surround the Calgary airport. So we got a mini airshow as one of the neighbours took off.


Two of the chassis were based on off-road RC toys. I had thought of this when I was considering the cost of building my own chassis, because it was several times less expensive. But they don't have very big tires, or very much ground clearance, so they got stuck. A lot.



This little robot, called 'Y Not' had the biggest tires, (Vex tires, I think), and was best at moving over the rough gravel and going uphill. I think at some point the phone/gps interface died, so it was pretty much just going in straight-ish lines.

Note to future robot builders: Hazards can be tough for rangefinders to spot, if they look like 'ground' 


And just because a hazard is marked by a cone doesn't mean you still can't fall into it. There were a few of these outlet pipes, and some were bigger than the robots. I think the cones were more so the people didn't break an ankle.



The official start. For some a press of a button, for others a battery connection. Or 'Wait, what? Start?'. LOL!


 There was lots of helping hands to keep things moving along.


There was also a fair bit of chasing after 'bots to keep them going at least sort of the right way. The grass was much taller and thicker than it appears from a distance.


If you think you have enough torque to climb onto this road, but haven't tested it, then you don't. It's that simple. When you are a robot with 2" wheels those 3" rocks mean the slope is basically vertical. So if you can't climb vertically, you will get stuck.

After a few helpful pushes, the first two made it uphill, and onto the road. Pretty speedy over flat ground, but they were basically driving blind.


I love how this shot shows him 'catching some air'. Heh....


I wonder if the ultrasonic range finder was getting confused at the gate. I think they should have left it open, and had a goal area roped off so the spectators wouldn't get a 'bot to the shin.


One of the bots, Y Not, is still down on the course, having electrical trouble. This shot really shows the scale of the challenge, so to speak. If the bots were twice as big, the problems would seem half as small...


Note to self: Stiffer, bigger tires are better. The current tires on my rover are about this big, maybe a little bigger (120mm), but they are very soft, so most of the drive energy goes into deforming the rubber, instead of climbing. The was the only bot to actually climb the hill on it's own!



Woot! They make it across the finish with power to spare. Besides a couple of pit stops for electrical issues, this was certainly the most capable bot. It was powered by a Lego controller, so it doesn't take a whole lot of CPU to win at these things. Just some good solid design. Well done!



I did get indoors; I found out that we do have a pcb manufacturer here in town, so I may have a few boards made now that I know I won't be stuck paying for shipping or customs. Yay!


Totally unfair fight: Roomba vs skateboard vs hex walker.


Surprise! Jay Ingram. Well, sort of a surprise, anyway. I heard he was going to be there, but I didn't see him until I was inside waiting for the awards to start. This little cardboard robot was roaming around, and it must have recognized him, because it kept running into his leg.


 The awards start. They pretty much took over the museum for the day. I'm not sure I'd want the rover motoring around indoors on automatic drive in this place... I could see a lot scratched paint happening...


Jay took a minute to talk about Beakerhead, so you should go check that out as well. I have no idea exactly what they are about, so I'll have to check it out, too, and have the rover tag along. Maybe when it isn't lasering rocks I'll put an umbrella on it's head and make it serve drinks at their social events, or something.


Awards start... some for the older folks (ok, these guys are totally younger than me...)

But mostly for the younger engineers. Good crowd. And Jay did a little quiet coaching so they wouldn't just stare at their shoes... pretty cool dude.


Ok, remember the robot 'Y not'? (it's actually spelled Y with a line over it, as in 'not' or inverted signal, but I have no idea how to type that...). They had a big trip from somewhere down south, so by now the kids were toast.

But Jay didn't mind; I think he was really encouraged by the number of kids that are going to be making the robots that take care of you and I when we get old, visiting new planets, and doing micro-surgery in our bloodstream. Just look at that grin...





WCRS Games today!

I'm heading down to the 20th Annual Western Canadian Robot Games a little later today, but the 'rover won't be competing :(

The rover isn't mobile yet, after I found the long cables from the body to the steering servos and the motor encoders were picking up to much noise from the motor power wiring, and I'm not done with assembling and coding the circuit boards to move those functions out to the wheels.

I did make some other progress, you can see here I'm fiddling with pullup resistors to get the I2C bus 'just right'. The water bottle on the right gives a sense of scale; it's about the same size as Sojourner, although the wheels don't fold up for a trip to Mars...


That mass of wires on the top? All breadboard-bound... I've learned the hard way that if it doesn't work on a breadboard, there is no way doing a cleaner job on a soldered protoboard is going to make it 'better'. Here is the view of the rats-nest:


The other big things done (or tested) are adding a connector to the Adafruit Ultimate GPS + Logger board, so I can attach both it's host Arduino Leonardo and the SD writer as SPI slaves to the Max32, instead of having the SD card as an SPI slave to the Leonardo. The SPI code examples for the SD library compiled and I was reading and writing to the SD card from the Chipkit Max32 on the first try, so that's a relief. Now I can start logging to the SD, and storing the menu system for the hand controller in a file on the SD card instead of hard-coded in the Max32.

With another whole year until the 2014 games I might start a bit simpler and eliminate some of the additional Atmel chips and just use the Max32 with a LOT more stuff on it's I2C bus. The big reason is that with such short summers here in Calgary I'd like to spend most of the time doing test drives outdoors, and not fiddling with custom PCB's - I can save that for the winter.

Look for some driving videos over the next two weeks, and hopefully I'll have a few good snapshots of the Robot Games from today in the next post.

Monday, May 6, 2013

Atmel Fuses and Tuning

(edit: I found this post stuck in draft mode, and decided to post it as-is for reference).

If you need to control your Atmel chip startup behaviour, you probably want to set the fuse bits. It's a little like burning eeprom settings; these don't get overwritten unless you mean to (or you hit the 'burn bootloader' in the IDE, even if no bootloader gets sent to the AT Tiny...)

First, check out the fuse values that you want here ... fuses are basically three bytes of data (low, high, extended):

http://www.engbedded.com/fusecalc

And then either edit boards.txt, or just do it at the command line with avrdude... start with this tutorial.

For a serial-GPS to AT 84 gadget I'm building I'd like to set 8Mhz, internal oscillator, and no clock/8, so that means the low fuse byte is going to be 'E2', the high fuse is 'DF', and the extended fuse is 'FF'. For some reason that isn't clear to me yet the unused bits in the extended fuse are read inverted by avrdude, so it might be read as '01'.

You might notice that I set the chip to use it's own slightly less than accurate internal oscillator. I'm cheap, and I don't need 16Mhz for this project (yet!) so 8Mhz is fine, but I'm also relying on sort-of-accurate timing because both the serial side and the I2C side of the communications are not implemented in hardware in the AT 84, but software, so it's probably safer to set the calibration before I end up troubleshooting what I suspect is bad comm wiring, when it's really bad timing.

How to do this? Tiny Tuner!

http://arduino.cc/forum/index.php/topic,8553.0.html




The Saga of the Simple On-Off Switch

Sometimes what should be simple isn't, and what shouldn't be simple is. Case in point: the humble on-off switch.

Before I started designing the current incarnation of the rover I had already started to build the control panel for the power switches. Pretty early on you'll learn that it can be simpler to keep the power supplies for logic and motors power separate; that way you can have different voltage levels for the two without spendy (and possibly inefficient) voltage regulators to cut the drive power levels down to something the logic can use. I also wanted a Run/Stop switch, so the rover could be powered up in auto-navigation mode, but hold it's position until told it was ok to start driving.

Turns out these switches, as beefy as they look, are only rated to ~20A at 12v (I think). At a possible draw of 15A each for the left and right side, I'd look pretty silly if a motor stall caused the switch to weld itself together and start a fire. So I put in one for logic (blue), and two for the left and right drive (red).

And of course there should be some LED's. Just because. (there are actually LED's here; three on the switches, and three just under the switches). The two larger holes under the switches were going to be for panel-mount fuses, but I decided that 'fuses are for sissies'. We'll see about that part... see my prior comments on 'fire'...



Fast-forward to my first drive test with the new rover, and after a round of steering tests I decided to measure the voltage on the drive battery, and it was something like 14 or 15 volts.

Gulp.

It's a 6s LiPO, so the operational range is 25.2v fresh, and 19.2v at minimum; maybe a little more for a safety margin. Below 19.2v discharge (lower than 3.2v per cell) and LiPO's become unhappy, and have shorter lives. The battery seems to have bounced back after a balance charge; time will tell if it really did get damaged.

I always had it in the back of my head to feed the drive and logic power to a pair of voltage dividers, and then measure that with one of the micro-controllers. So before I could continue with development I had to stop and complete that item on the checklist. And at about the same time I had just seen that doing the analog-to-digital conversions over long, noise inducing wires was a Bad Idea.

Redesign time!

The parts bucket had a few Atmel Attiny's in it, and after some doodling some possible pinouts I settled on using the Attiny 84 on a small protoboard on the back of the panel to do the ADC and drive the LED's. Turns out that the missle switches I was using have to be wired in an interesting way to get control of the LED somewhat separately from the switch itself.

And since I had two PWM controlled fans mounted just under the panel, near the motor drive PCB's, and a handful of TMP36 temperature sensors looking for a home, I thought that I'd throw in some logic to control the fan speed based on temperature. For good measure I also wanted a servo to control some physical vents, so I could keep the rover body warm; at least relatively warm, as not everything is rated to -40C (or F, take your pick) and cold/hot cycles can be harsh on things.

So now I had a design to hold the voltage dividers, temperature sensor, NPN transistors for LED control, a button input for the Run/Stop switch, a fan PWM output, and a vent servo output. Add in an I2C interface, and every pin on the '84 had a job to do. It looks like this:

Hardware: AT Tiny 84

         PORT SW HW | HW SW PORT
       --- Vcc -- 1 | 14 -- GND ---
LED_VLOG GP PB0 0 2 | 13 10 PA0 ADC ADC_VLOG
   SW_RS GP PB1 1 3 | 12 9 PA1 ADC ADC_VDRV
       RST PB3 11 4 | 11 8 PA2 ADC ADC_TEMP
PWM_RS INT0 PB2 2 5 | 10 7 PA3 ADC LED_VDRV
PWM_FAN PWM PA7 3 6 | 9  6 PA4 I2C SCL
    SDA I2C PA6 4 7 | 8  5 PA5 PWM VENT_PWM

I didn't realize it at the time, but there are some challenges to doing this with the Arduino IDE and the tiny-core, as good as they both are.

First, the pin names for analogRead are a bit whacked out, and need to use the analog pin names instead of the pin numbers. So analogRead(8) won't work, but analogRead(A2) does. I had tinkered with direct ADC register reads/writes, but analogRead works just fine. I found that I had to carefully build the statement to preserve the float math wrapped in a round() function to get the degrees C the way I wanted it, which is a single byte integer. I haven't tested low temperatures yet, but a byte should hold the range the TMP36 works in just fine, as +/-127C. It probably bottoms out at zero right now.... Hmmm... Anyway...

In my quest to nail down the conversion math (10mV/degree C) I added a 0.1uF cap across the TMP36, and the readings are now much more stable, even on wires long enough to reach down into the body nearer the driver IC's on the MD10C's. I guess I need to order another box-o-caps, since those were supposed to be for decoupling the microcontrollers.

The other trap I fell into was labeling the pin for servo control as 'PWM' and misleading myself. Servos don't use raw PWM, they use a 20ms recurring pulse between 500usec and 2500usec long. SoftwareServo works, but it looks like a hack; needing a call to ::refresh every 20ms or so. Yuck.

So I adapted the idea of using Timer1 interrupts on both match and overflow to control the pulse width and cycle time, respectively, and loop through 3 possible servos, one every 8ms, for a 24ms refresh rate. Better! But it took a couple of days to get it just right. It also means that any pin could do servo control, and you don't need to tie the physical design to where OCxx appears as raw PWM output... but it is handy to use similar pins since in my case OC1B gets messed up by my Timer1 takeover anyway. I stay well away from Timer0, since I need that for base functions like millis(). I think it would mess with I2C as well. Also, Timer1 is 16 bit, which is needed for getting the servo timing durations right with the '84 running on the 8MHz internal oscillator. Prescaler = 1/64, 10 bit fast PWM mode, if you care.

The last minor issue was getting TinyWire to do the I2C stuff just right. It works like a charm. The '84 is pretty busy, so it doesn't always respond to I2C, but it never misses two requests in a row, and only misses one or two every minute or two, if polled once per second.

There were a couple of items that turned out to be simple, in the end. At this point in the build, it was a pleasant surprise...

If anyone needs to know, I poll I2C from the ChipKit Max32, which is a 3.3v device, but unlike the ChipKit Uno it has I2C pins that are 5v tolerant, so I pull those up to 5v. No problems there.

Similarly simple, the fans, Arctic Cooler F80's, will take 'normal' PWM as generated by analogWrite, so you don't need to mess with timers or anything. I use OC0B, which is on Timer0, so it's not affected by my Timer1 use. They won't fully stop spinning at PWM 0, but that's ok. I suppose I could do something clever with the PWM driving a separate MOSFET to control the input voltage... next time.

The reason there are two fans is simple; they are PC case fans designed for 12v, a voltage I don't have, so I wired them in series and fed them from the ~24v drive power. They seem quiet enough, although I'd choose a fan with a lot more CFM next time, regardless of noise.

Oh, the key lock on the panel? That was simple too. The Run/Stop switch is wired through it; if the rover is ever out in public I can lock the R/S switch 'off', so if a small finger finds the glowy button the rover won't think it's starting a race and run over the poor kid, dog, or foot. Simple.

Here is the final protoboard, with only a few minor fix ups. On a side note, the Adafruit protoboards are terrific to work with - way better than wasting time with cruddy boards to save $2.


From top-left (at about the 11pm position), there is the Run/Stop header; I added a transistor there to boost the brightness a wee bit. No there are no limiting resistors. Yes, I'm rethinking that.

At the top-center (right above the AT84 chip) is the vent servo connector, and the fan pwm pin. The fan pwm comes directly off the AT84, so there is no visible jumper wire. Normally I like to arrange things so I can take advantage of a 5-pad protoboard, but it didn't work out in many places this time.

The four resistors are the voltage divider that take the 8.4v and 25.2v from the batteries and cut them down to just under 5v. If I had to do it again I'd use a 3.3v reference, so I wouldn't have to deal with trying to measure 5v with a questionable 5v reference.

The next batch of resistors and transistors on the right side are the LED drivers (sinks, actually...), all NPN's. Originally there were only two, but I realized the way I was using one transistor to light the LED's on two switches would probably be a Bad Idea, since it would bridge the power circuit on a jumper wire on this board, with no current limiting. Yikes!

The big 8 pin connector is the interface to all the wiring on the panel itself. This is so I can remove the protoboard without dragging the entire panel off the rover.

The two connectors on the bottom left (at about the 7 and 8 o'clock positions) are two I2C interfaces; one is an input to the board from the Max32, the other continues on to an RJ-45 connector on the panel itself, so I can plug in an I2C hand controller for testing and manual driving on the end of a standard ethernet cable. These connectors supply everything to the board; power, ground, I2C clock (SCL), I2C data (SDA), servo power, and the last pin is a passthru loop from the hand controller, so if it gets disconnected I can sense it right away. This layout is my standard interface for I2C things, although not all need to have servo power or the loopback wire connected.

The observant among you might notice there isn't a 0.1uF cap across the Attiny yet. I'll wedge it in there somehow.

All of this goop gets tied to a set of registers that control the logic, and are accessible via I2C. Here is the register map:

#define STA 0
#define VER 0 // EEPROM VER
#define I2C_ADDR 1 // This modules I2C ADDR
#define EEPROM_LEN 2 // Amount of reg to store in EEPROM
#define REG_END 3 // Save len for registers
#define VLOG_LOWLIM 4 // Scaled ADC warning level, 6.4v
#define VDRV_LOWLIM 5 // Scaled ADC warning level, 19.2v
#define TEMP_MAX 6 // DEGC to throw warning
#define FAN_ONVAL 7 // DEGC to start fan
#define FAN_OFFVAL 8 // DEGC to stop fan
#define FAN_CMD 9 // Fan prog: auto, on, off
#define VENT_SERVOLOLIM 10 // Servo limit
#define VENT_SERVOHILIM 11 // Servo limit
#define VENT_PWM_VAL 12 // Servo PWM Value
#define VENT_CMD 13 // Vent prog: auto, open, closed
#define FAN_PWM_VAL 14 // Fan PWM Value
#define WEB_DEGC 15 // Scaled ADC
#define RS_SWITCH_VAL 16 // Switch state
#define RS_LED_PWM 17 // RS LED 'Throbber'
#define RS_LED_CMD 18 // RS prog: see table
#define VLOG_VOLTS 19 // Scaled ADC
#define VDRV_VOLTS 20 // Scaled ADC
#define VLOG_LED 21 // On=ready, fast=low voltage
#define VDRV_LED 22 // On=ready, fast=low voltage
#define EXEC_STATUS 23 // Chassis EXEC thinks we are ready (or not)

In a (hopefully) final ironic twist I may add a regulator off the drive power so this little guy will always have at least a stable 5v in case the logic battery is low, and the ADC readings go wonky. I think to handle the step down from 24v it's going to be spendy, like $25 for a DE-SWADJ 3. ~95% efficient, though.

It needs a cooler name, too. I refer to it collectively as 'the panel' now. Boring. Maybe something that makes an acronym. Or not, the world has enough acronyms. Maybe 'Jeff'... "Hey, hit the red switches on the Jeff, m'kay?" Probably the whole rover would then get called Jeff though, as it doesn't have a name, it's just 'Rover'. I'll stick with 'Panel' for now.

What started out as a simple on-off switch sure grew legs, huh?