September 2009 Archives

Storing data in the eeprom of an ATMega168

| No Comments
Some of the new commands that I have planned for the servo controller will require that I load and save persistent settings from the ATMega's eeprom. Having spent a little time looking at the example code in the datasheets it seems that you have to disable interrupts to safely read and write the eeprom. It's not a problem to have interrupts disabled whilst I read the settings when the processor boots up but allowing new values to be written back to the eeprom as the result of a serial command will be problematic given the interrupt driven nature of our PWM pulse train.

This seems to require that we can stop the PWM generation completely and only allow the eeprom update commands to be executed when the controller is in 'stopped' mode. This isn't too much of a problem as I envisage that these settings would be configured infrequently and doing so with the controller in a 'paused' state is OK.

A last minute addition to the currently available code was to add a servo controller information query command, send an [0x00] to the controller and it will return a four byte response [0x00] [versionMajor] [versionMinor] [numServos]. The current software returns 0x00 0x06 0x00 0x40 which is v6.0 supporting 64 servos. As I add new functionality any control software that uses the controller can determine if the new functionality is supported by the controller by querying the version.

Two additional commands, for safe eeprom programming are [0x01] to enable PWM generation and [0x02] to disable it. Commands that write to the eeprom can only be executed when PWM generation is disabled.

The easiest new commands that use the eeprom data store are to set the minimum and maximum position for a servo. Asking to move a servo beyond its minimum or maximum positions can either result in an error and no movement or movement that is curtailed by the limit that is exceeded. I expect whether it's an error or whether the movement is constrained should be a controller configuration property; I don't want to have to download new firmware to change the behaviour and I don't yet know which behaviour is most appropriate... We already have a limit on the maximum servo position, set to 0xFE, so we simply need to check the maximum against our new, configurable value and add a check for a minimum. This expands the size of the 'per servo data' and we can load the values from eeprom when we boot and save them on demand. I expect it will be best to have one set of commands to query and set the min and max values for each servo and a separate command to write all updated values back to eeprom. 

ATMega168 64 channel servo controller

| 2 Comments
This is the source code for the latest version of the 64 channel servo controller as detailed here.

This is an ATMega168 version of the controller that was originally developed for the ATtiny2313 but which was ported to the ATMega when I ran out of memory on the ATtiny.

The schematic required is similar to the one for the ATtiny2313, I'll produce a new one for the ATMega168 when I get some time. Note that we now use pins 0-3 of port B and port C rather than just 0-7 on port B, so the connections for mux chips 5 through 8 will come off of port C.

Source code is available here.

New servo controller commands

| No Comments
The new 64 channel ATMega168 serial servo controller accepts the following commands. All successful commands are echoed back. Parameters are validated and errors are indicated with an error response of [0xFF] [badParamIndex] [Command echo] where badParamIndex is a 1 based index of the parameters in the command and indicates which parameter failed validation.

  • Set Servo Position
    [0x41] [servo] [position] - This command operates in the same way as the standard SSC compatible servo command that the original servo controllers supported. That is the servo specified is moved directly to the position specified. The servo index should be between 0 and the number of servos that the controller supports (up to 64) and the position should be between 0 and 254. A position of 127 sets the servo to the centre. 
  • Delayed Set Servo Position
    [0x42] [servo] [position] [stepSize] - This command will cause the servo to move from where it currently is to the desired position in steps of the specified size. A step is taken each time the PWM pulse refreshes, so 20 times per second. If the servo is currently at position 0 and you want it to move to position 100 and you specify a step size of 1 then it will take around 5 seconds to reach the final destination. With a step size of 2 it would take around 2.5 seconds, etc. Note that the actual time taken will be affected by the speed of the servo. If you specify a step size of larger than the distance between the current position and the desired position then the servo moves to the new position straight away. The command is echoed once it is actioned and an asynchronous 'move complete' notification is generated once the servo arrives at its desired destination. The move complete notification is in the form: [0xFE] [servo] [position]. At any time between starting the move and the move completing you can send a stop command to stop the servo at the point where it currently is.
  • Delayed Set Servo Position with step frequency control
    [0x43] [servo] [position] [stepSize] [stepFrequency] - This command is the same as the command above except that the frequency of steps can also be controlled. The command above is equivalent to this command with a stepFrequency of 1. If the servo is currently at position 0 and you want to move it to position 100 and you specify a step size of 1 and a frequency of 2 then it will take around 10 seconds to reach the final destination.
  • Stop Servo
    [0x44] [servo] - This command will stop the servo moving if it is currently moving as part of a delayed move command. The current status of the servo at the time it was stopped is returned in a servo stop response which is sent after the stop servo command has been echoed and actioned. The servo stopped response is in the form: [0xFD] [servo] [currentPos] [stepFrequency] [targetPosition] [stepSize] where the current position is the position of the servo after it has stopped and the stepFrequency is the frequency with which it was moving before it was stopped. If the stepFrequency is zero then the servo was already stationary.
  • Stop Servos
    [0x45] [numServos] [servo1] [servo2] ... [servoN] - This command will stop all of the servos specified and will generate a servo stopped response for each one.
  • Stop All Servos
    [0x46] - This command stops all of the controller's servos and generates a servo stopped response for each one.
  • Query Servo
  • [0x47] [servo] - This command will query the current position of the specified servo and return it as a servo query response after the command echo. The servo query response is identical to the servo stop response except the response code is 0xFC rather than 0xFD. Note that if the stepFrequency is zero then the servo is stationary. If the stepFrequency is non zero and the currentPos is not equal to the targetPos then the servo is moving.
  • Query Servos
    [0x48] [numServos] [servo1] [servo2] ... [servoN] - This command will query all of the servos specified and will generate a servo query response for each one.
  • Query All Servos
    [0x49] -  This command queries all of the controller's servos and generates a servo query response for each one.
As you can see, this controller gives me much more control over the movement of the servos attached to it. The main thing being that I can stop servos in mid move if required and that I can move servos at slower than maximum speed. This paves the way for being able to simplify the logic in the actual microcontroller that generates the movement sequences required to move the legs whilst still being able to monitor for collisions and stop the servos in mid step if the sensors on the legs indicate that it's necessary. 

Of course, first I actually have to build more than one leg, but before I move on to that there are a couple more servo controller commands to implement. The first being the ability to set several servos to move to new positions in such a way that they arrive there at the same time. This was the reason for the stepSize and stepFrequency elements of the delayed move commands. Ideally the servo controller will do the calculations required which means that the 'gait generator' just needs to know where to put the feet rather than how to move each servo at the right speed so that the foot ends up in the right place at the right time... Next will be the ability to provide a mapping table between 'logical' servo indexes and physical servos, this is so that if it happens to be difficult to get all of the tracks on the board to end up in the right places I can adjust which logical servo is controlled by which pin. This will involve accessing the eeprom of the ATMega168... Once that's done it would be useful to have the ability to set the 'default starting position' for each servo, so that they can start at positions other than 127 without there being a race between the controller starting up and the servos all ending up in odd positions. Finally as a safety feature being able to set a minimum and maximum position for each servo would be useful.

Source code for the current version of the controller will be available soon.

Moving forward

| No Comments
Due to work pressure and then holidays and then more work pressure I had to take a break from the servo controller for a couple of weeks. Most of the code changes that I had previously been discussing have been implemented and I'm now in the process of testing an ATMega168 version of the 64 channel servo controller complete with new style commands! Since this version of the servo controller uses a custom serial protocol and since it can send unsolicited serial responses back to its controller I needed to write a new PC based control program to test it with. That's now operational and I've been testing the delayed moves and their corresponding asynchronous move completion notifications. Once I'm happy with that I need to design and write the final piece of code which will interface between the new serial protocol and the servo control data update code... I've already implemented the move completion notifications, servo position query, servo stop and stop all servos commands so the design of the data structures and synchronisation details have been validated. Once that's done and working on the 168 I may see if I can squeeze an 8 channel version of this new code back onto the ATTiny2313. 

About this Archive

This page is an archive of entries from September 2009 listed from newest to oldest.

August 2009 is the previous archive.

October 2009 is the next archive.

Find recent content on the main index or look in the archives to find all content.