Recently in Servos Category

Bug in v7.0 of the servo controller firmware

| 1 Comment
The simple servo sequencer that I've been working on has exposed a bug in the servo controller firmware. The bug is due to stack corruption during movement completion notifications, so it only happens if you use the 'multi-move' commands or the delay move command. The problem is that at the end of SerialSendMoveCompletionNotification we jump back to the serial data accumulation loop rather than using a ret to return... Since we enter SerialSendMoveCompletionNotification via a call rather than a jump we are failing to balance the stack and so eating two bytes each time we call the function. Eventually the stack usage will  start to overwrite our data space and cause 'strangeness'. The fix is simple, remove the jump and replace it with a ret.

The sequencer has also exposed an issue which I think lies with my current servos. After continuous 'stepping'; i.e. running the single leg as if it were walking for around 40-50 commands (15 steps), some of the servos start to slow down, there doesn't seem to be anything wrong with the servo controller as the TextStar Serial LCD Display in "Servo monitor mode" was showing that the signals were still good and my multimeter showed that the servos weren't trying to pull too much power. It seems to be a torque or heat issue; more investigation is required, but things seem fine if I'm just running servos that don't have a load on them...

Sensing servo torque

| No Comments
Whilst playing around with my servo controller I realised that the power used by a servo goes up considerably when it's under heavy load (such as when it's pressing against the table and still trying to move). I can, potentially, get an idea of this load by measuring the current that each servo is using and using this feedback somehow. I've yet to work out how, but at the very least it could be used to protect the servos against overloading; if the load gets above a certain threshold then stop moving! Ideally the servo controller could feed this information back to the user of the servo controller as well. Anyway, this requires quite a large amount of breadboarding changes, the use of some active low multiplexor chips and some playing around with the ADC on the ATMega. I don't think I'll experiment with this just yet...
This is the AVR Studio project and assembly language source code files for the latest version (v7.0) of my 64 channel serial servo controller.

This is the latest version of the ATMega168 version of the code which includes all of the new servo commands that I wrote about here including the multi-move command and the unit tests that I spoke of here. The controller allows you to set minimum, maximum and startup servo positions for each servo which can be saved into eeprom and used every time the controller is powered up. It also includes a programmable, per servo, "centre adjust" value which can be used to adjust for servos that are installed slightly off centre.

Source code is available here.


Back to JIT testing

| No Comments
The latest version of the serial servo controller is now fully operational (I'll upload the source code shortly). There are still some bugs that I'm finding but the work I put in to getting the unit tests in place makes fixing these bugs pretty straight forward. Whilst I have pretty much 100% coverage for the simpler serial commands I've stopped writing tests for the 'multi-move' command now and I've switched to "Just in time" testing; that is I write a test in response to finding a bug. The test duplicates the input that causes the bug to show up and then I fix the bug using the test harness to exercise the code with the correct input values... It would be nice to stay focused on getting 100% coverage on the multi-move command but right now that's not a priority. 

Whilst developing the servo controller I often wished I had an oscilloscope, being able to visualise the signals that I was generating would have been useful many times. Due to the cost, choice and the fact that I eventually worked out what I was doing wrong in each situation I am continuing to delay getting an oscilloscope but today I saw a cheap little device that could be useful as I tune the controller in future. My 'new products' feed from CoolComponents had the TextStar Serial LCD Display in it this morning. This is a neat little programmable display which has a 'servo signal display' mode which enables it to display the pulse length and refresh rate of a servo signal. Given the cheap price and the fact that I'm sure the LCD display in itself will be useful I ordered one. I hope to hook it up to my controller so that I can see what's being generated. The datasheet for the device is here.

Testing backwards

| No Comments
It's taken me almost a month but I'm finally back to working on integrating the multiple servo move command into the rest of the code. Well, the integration was done long ago, unfortunately the debugging was the bit that was taking up my time.

I decided that putting 'printf' style debug output into the routine to attempt to debug it from my PC based control software was just the wrong way to go about finding the problems and so I set off on a mission to finally get some unit testing into my code. This worked out well and I now have over 80 tests for all of the serial command code. I found a few subtle bugs and I'm in a much better position for reactoring away some duplicate code and other design smells. I also feel much more confident about making the other wide ranging changes that I will eventually make when I switch to using interrupt driven serial comms and move to a 16bit control value for the PWM signals...

So now I have to write the tests for the code that I know has some bugs in it... The problem I have with the code under test is that it's quite big. In fact it's quite a bit bigger, and more complex, than all of the other serial protocol routines that I've tested. The initial tests are easy enough, parameter validation etc, but the main tests involve me testing a large block of code that appears to have at least one 'oh dear I've gone off into an infinite loop' bug in it somewhere under some input data conditions... At first I thought I would have to break the code down into smaller functions that were easier to test and then I realised that I can already test the code in smaller sections, just as long as I do so backwards.

The code is one long function that we jump into and which jumps back out to the command accumulation loop. Throughout the code there are various labels that break up the various sections of the code. If I structure my tests so that I test the code from the end back towards the front I can simply set up the environment with the data that each stage expects and then jump to a label that processes the data. So, if the code takes input data at A and then processes it via B, C, D, E and F, I can first test pushing the kind of data that E should produce by jumping to F. Once that's works I can test E with the data that D would produce, etc... Once I get to A the whole thing is tested...

We'll see how it goes...

Relative branch out of reach

| No Comments
The test code for the serial command processing code for my serial servo controller is turning out to be the largest piece of assembly language that I've written. This means that all of a sudden I'm coming across "Relative branch out of reach" errors during the compile. I've got to a point where every time I add a test I have shuffled the code to such an extent that several relative branches need adjusting from rjmp to jmp or rcall to call. Not a great problem but, of course, jmp and call take up more space so the first round of adjustments often triggers a second round, etc. It seems that once you get to the point where your code needs jmp and call its size can just explode due to the fact that you now need to use jmp and call...

Ah well, it's not a problem really... I'm now at 66 tests and 59% of my code space used up. I've got pretty complete coverage up to the "stop servos" command. I have the query commands to test and then I'm finally on to the multiple servo move command... Then I have the PWM code to test, but I expect I'll take a break from the testing for a while once I get the multiple servo move command to actually work!

Integrating the multi-move command

| No Comments
I'm in the process of integrating the stand alone code that implements my 'multi-servo move' command and the rest of the controller. It's harder than it should be, probably because I'm not experienced enough yet with assembly language not to have made some school boy errors. Once again I've run out of registers, mainly because I'm trying not to have to push stuff on the stack that often. I've been juggling with the limited number of registers and up until now it's worked but...

The first problem is that I need two pointers to be able to do the data sorting for the multi-move command. Up until now all of the serial code has only ever had to use one pointer. I've been using X in the serial code and Y and Z in the PWM code. My usage of both Y and Z precludes me sharing them with the non interrupt code, which is a shame. The reason I can't share Z is because I'm using it to switch between modes in the timer interrupt; I use ijmp which is an indirect jump using Z to select which interrupt handler I need to call next time around. This is cute but hardly necessary... Removing this use of Z means that I can use it in the serial code as well, now that it's just a normal register pair I can simply push it onto the stack during the PWM setup code that also needs to use it for sorting... 

My second problem is that I should always have simply been pushing registers onto the stack when I entered the PWM setup routine. Instead I tried very hard to simply not share registers between the PWM code and the serial code. Unfortunately I've no pretty much run out and so have to go back into the code and adjust the register usage which is a pain and error prone...

Anyway, that's almost done now and, hopefully, the rest of the integration will be straight forward.

After the servo controller

| No Comments
The work on turning my excel spreadsheet into AVR assembler code which can move multiple servos to arrive at their target locations at the same time is proceeding well. I have the required code operating in a stand alone environment in the simulator and all I need to do now is merge that in with the rest of the code... Once that's done my servo controller is complete and whilst I already know that there are at least two further versions in the pipeline I expect I'll move onto something more before working on them. 

This weekend I sketched out some ideas for the next programming phase; the servo sequencer or 'gait controller'. This will initially be written in C++ and run on a PC but the design sketches that I did this weekend were for the microprocessor version. The plan is that the servo sequencer is a state machine which can be triggered off of servo move completions and timers. The idea being that it can be programmed to know about a sequence of moves (such as all of the moves required to move a 6 legged robot in a forward direction) and then be told to execute those moves. The sequencer would then manage this and other processors would deal with sensors and other decisions (such as exactly where the feet should land or exactly how the body should be angled, etc.). The sequencer can be isolated from these things a little by allowing the other controllers to tell it the detail (i.e. where exactly each three servos for each leg should be) but the sequencer itself would know that it moves this leg after that leg etc. Step length, step depth and body orientation can then be adjusted by tuning parameters that the overall sequence of steps uses without changing the state machine that makes the middle left leg move after the front right, or whatever.

My current ideas for the microprocessor version of the sequencer are quite ambitious; but then that's the point really, these micro projects should be pushing me forward and shouldn't be easy. The sequencer, since it's essentially a programmable state machine, needs to be able to allocate manipulate and free various blocks of memory; so it seems that I'll be building a dynamic memory allocator at some point. It will use interrupt driven serial I/O; and once that's done that work can be used for the next version of the servo controller. It will need to speak to the PC so that a PC program can be used to controller the sequencer (until the next level of robot controller is conceived and then designed) and it needs to talk to the servo controller to actually move the legs (this may be two UARTS; potentially meaning I have to create the second without hardware support and bit-bang the comms out, or perhaps serial to the PC and TWI/I2C to the servo controller). The sequencer's state machine is driven by the completion of delayed moves from the servo controller; so we can kick of a sequence by actioning the first state and then wait for the completion to trigger the state transition. Additionally a state transition can set a timer which can later trigger a new state transition. The programmable timer code will need to be developed... 

Deliberately the sequencer will not be limited to controlling blocks of 3 servos. This wont be a hexapod sequencer but a generic servo sequencer that will work with the servo controller that I'm currently finishing. So, theoretically when I want to develop l'arachnid once l'hexapod is complete I can 'simply' switch to using 8 x 4 servo legs and the same firmware...

However, the fact that I've now got to the point where I've almost completed a 'non-trivial' assembler project means that I feel I'm able to move the hardware side of the project forward. So I expect that once the servo controller is complete and whilst the sequencer is being designed I'll try and get to a point where I actually have the required number of servos and a 6 legged robot to control...

Moving multiple servos at once

| No Comments
The final command for my serial servo controller is the most complex. The idea behind it is that with a hexapod leg you will want to be able to move the leg to a new position where the new position requires all three of the servos that manage the leg to move to potentially new locations. Ideally you want the "foot" to arrive at the final resting place in such a way that all of the servos complete their moves at the same time. Since each servo will likely have to move a different distance from where it is now to where you want it to be and since I don't want to have to burden the code that determines how the legs themselves move with this kind of knowledge I decided to build the functionality into the servo controller. My design decision was validated somewhat when I discovered that the SSC-32 servo controller can do this.

I have all of the pieces in place to be able to do this, but as always, the devil is in the detail. To be able to move several servos from one place to another so that they arrive at the same time I first implemented commands that allow me to move servos at less than their maximum speed. This resulted in the two "delayed move" commands that are present in the current version of the servo controller. The idea is that you can have the servo controller take a target position and a step size and a step frequency and it will deal with moving the servo gradually from its current position to the target position (and then notify you when the servo has completed the move). This works well and the functionality is essential for getting the multiple servo "move as one" command to work. 

With the multiple servo command I need to take several new target positions and then calculate the required step sizes and step speeds for each of the servos so that they can all arrive at their target positions at the same time. For example, if we have two servos, both currently at position 0, and we wish to move servo A to position 100 and servo B to position 50 it's fairly obvious that B has to move half the distance that A has to move and as such if A were stepping 1 step every cycle then B needs to step 1 step every other cycle for them to arrive at their target positions at the same time. It's less easy to see that if servo B needs to move to position 77 then it needs to step with a step size of 3 every 4 cycles and that we need to fudge its start point by one step (of 3) to ensure that it actually arrives at the target (rather than at position 75).

Essentially we're interested in calculating the smallest common factors between the maximum distance that needs to be moved (by the servo that needs to move farthest) and the distance that this particular servo needs to be moved. I've currently got a spreadsheet that can calculate the required step size and frequency values for given distance pairs, which is a start. Translating that into assembly shouldn't be too hard now that I understand what's needed.

Almost there....

| No Comments
Work on the latest version of the serial servo controller is going well. I'd accumulated a pile of random nice to have ideas, some of which then necessitated some other ideas, and then there was the one must have command (the one which moves several servos to new positions over time and ensures that they all arrive at their final resting places at the same time). Of course I've worked on some of the nice to haves rather than dealing with the final 'must have' command that I need before I can move on to writing some gait controlling software to move multiple legs in sequence...

The current software includes the ability to turn off the PWM generation completely and to turn it on again; this is needed so that the 'save settings to eeprom' code can work as that requires that we don't have interrupts enabled. I've added the ability to set minimum, maximum and initial positions for all servos. These values can be saved to eeprom so the controller remembers them. I've also added the ability to adjust the 'centre' position for a servo; you can say that a particular servo is centred at 100 for example, rather than 127 and then talk to it as if you're moving relative to a 127 centre and the controller will adjust accordingly. There are also three controller configuration options that can adjusted via serial commands and saved to eeprom. The first determines if the PWM generation is turned on after a reboot. If not then you have to turn it on yourself with the appropriate command. The next determines if the controller sends out a 'get info' response when it starts after a reset (I figure that this will be useful for downstream processors, if the servo controller is reset these other processors might need to know!). Finally there's a setting which determines what happens if you try and move a servo beyond the min or max position. By default such a command is considered to be in error and you get an error response. You can change this so that such a command is OK but the command echo indicates that although you tried to move to, say, 201 the limit is 200... I've also added a command which resets the controller; mainly for testing at the moment. The get info command for this version returns more information so that you can tell what the state of the various programmable options are.

Now, I really should get on with the 'move multiple and arrive together' command...

About this Archive

This page is an archive of recent entries in the Servos category.

Sensors is the previous category.

Source code is the next category.

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