Showing posts with label servos. Show all posts
Showing posts with label servos. Show all posts

Monday, October 17, 2011

Interesting servo hack

After reading a few other articles about hacking servos to make them rotate continuously, I noted quite a few people suggested disconnecting the rotary pot and replacing with a voltage divider made up of 2 x 2k resistors (in a sort-of Y shape)



Our servo is much too small to fit extra components inside it, but without these, it doesn't seem to work. It spins in one direction, by sending a repeating 1ms pulse every 20ms, but increase the pulse length to 2ms and instead of running in reverse, the servo just judders and makes a nasty noise.
(if the servo is "centred" at 1.5ms, a pulse of 1ms tells it to move 90 degrees in one direction, and a pulse of 2ms tells it to move 90 degrees from centre in the other direction. By removing the pot input, the servo never knows where the head is so should continue to move).

Removing the pot seems to have caused the problem.
To simulate the pot, we soldered a piece of wire from the board where it was connected to the potentiometer (we should have snipped the end nearest the pot, not nearest the board and we could have re-used the bit of wire without extra soldering!) and connected to a voltage divider on the breadboard, made up of two 2K pots



This sort-of solved the problem, but not quite.
The servo no longer judders, but it's not not right. With a pulse width of 1ms, the servo runs at full speed in one direction. A pulse width of 2ms makes it run in the same direction, only much slower.
Maybe this is because we're using power and ground on either side of our voltage divider, rather than taking them off the internal pot (but then to get at those wires would require completely dismantling the servo!)

Now we could play about with the resistor values, or maybe even replace them with an exterior potentiometer (with the wire from the servo connected to the wiper and each end connected to power and ground) but here's a thought....

Pulling the signal on the wire to ground causes the servo to run at full speed in one direction.
Pulling it to power (5v in our case) causes the servo to run at full speed in the other direction.
So now we have a binary method of moving the servos either forwards or backwards - simply connect this new wire to an output pin and pull it high to drive the servo in one direction, and pull it low to drive it the other way.




Edit...
interestingly, we did have to make some changes to the servo control values to get the servo to work consistently without juddering. When pulling the signal pin high, we set the servo signal length to zero. When pulling the signal pin low, we set the servo signal length to 2ms. This resulted in the servo running at full speed in opposite directions. (using a signal length of 1ms and pulling low occasionally caused juddering so we ditched it!)

The downside to this approach, of course, is that we don't have a way of programmatically stopping the servos from turning. For our little robots project, we'll live with this restriction.
It's a fine balance between coming up with a project that can be completed inside a couple of hours but still demonstrates "hardware hacking" and spending all day perfecting servo controls which probably wouldn't get used!

Anyway, this is to document how we hacked our micro servos to allow us to create little tiny robots, instead of the big monstrosities normally associated with continuous rotation servos ;-)

For anyone interested, here's the Oshonsoft BASIC PIC code for our servo test board:


Define CONF_WORD = 0x3f18
Define CLOCK_FREQUENCY = 4

declarations:
       Dim servolen As Word
       AllDigital

init:
       Config PORTB = Input
       Config PORTA = Output
       OPTION_REG.7 = 0 'pull-ups on PORT inputs
     
startup:
       While PORTB.0 <> 0
              'do nothing: we have to press the button to start
       Wend
     
loop:

       'button controls direction
       'connect the extra wire from the servo
       'to pin PORTA.1
       If PORTB.0 = 0 Then
              High PORTA.1
              servolen = 0
       Else
              Low PORTA.1
              servolen = 2000
       Endif
            
       'servo control signal
       'for our hacked servo, signal length doesn't matter
       High PORTA.0
       WaitUs servolen
       Low PORTA.0

       WaitMs 15

Goto loop
End

Hacking to make a continuous rotation servo

As part of the up-and-coming HackLlan show-and-tell session, and for the follow-up workshop, we're making robot kits in preparation for the Robot Week Wales.

As with most robotic projects, this begins with hacking some servos to make them rotate continuously. We could just buy factory-set rotational servos from our pals at Oomlout but as the workshop is to include "hardware hacking" we figured we'd have a got at modifying some micro servos.

We're after making some small, compact robots so these micro servos are the perfect size (plus of course, a ready-made continuous rotation servo is �11, a micro servo less than half this at �5 each). We already had a couple of these from an earlier project but if all goes well with this experiment, we'll be buying more!

At this stage, we're not sure if the modifications will work, but we've looked into how a servo works. It's basically a small motor with a control board. The output from the motor is geared right down, giving the servo plenty of torque (twisting power). The control board has a microcontroller and a rotary potentiometer, which is turned as the motor moves the servo "horn", which is connected to the shaft of the motor.

These easiest way to explain this is to have a look at what goes into a servo.
Whenever you take anything apart, the most important tool you can have is a digital camera - and a hammer. Hammers open anything ;-)


We put the hammer to one side and open up the servo with a tiny jeweller's screwdriver.
We actually found that the smallest flat-headed screwdriver worked better than even our smallest cross-headed 'driver (despite the servo having cross-headed screws holding it all together).

You can see that the motor shaft has plenty of cogs, gearing the output down many, many times. This is what gives the servo motor it's power.


Underneath the control board, you can just make out the rotary potentiometer. As the motor turns, the gears and cogs also turn, and the shaft on the second "pile" of cogs causes the wiper on the potentiometer to turn. This signal is fed back onto the control board, so that when the servo head has reached the required position, it knows to stop turning the motor.


We traced the wire from the pot to where it meets the control board. Taking photos (so it can be replaced later if necessary) we snipped the wire from the pot and taped it up. Now, when the motor turns, the control board won't know where the servo head is, and so will keep turning the motor.

The last thing to amend is the physical lock on the servo head.
A small "lug" on one of the cogs stops the head from turning too far during normal operation.


We snipped this lug off the cog and reassembled the servo, using the earlier photographs as reference. We then put the head back on the servo and turned it by hand, to check that it does, indeed, turn through 360 degrees. The last thing to do now is to check that the servo direction can be controlled by our microcontroller.....

Sunday, May 15, 2011

Loads of servos!

Just a quick post showing the latest version of the USB servo controller board, driving six independent servos at a time (it was going to be eight, as we'd originally ordered six servos off eBay to go with the two we've been testing with. They finally arrived yesteryday, but two of them don't seem to work properly - the servos chatter and sound terrible, whatever position they're moved to - so we've left them off the video.)
But as a proof-of-concept, it works pretty well:


The two (older) servos on the right seem to move in the opposite direction to the smaller, newer 9g ones. Maybe because they're by different manufacturers? Or maybe they're meant to be mounted the other way around - who knows??

For anyone interested, here's the full script of the animation being played out:


label 900,1
servo 1000,8,150
servo 1000,9,150
servo 1000,10,150
servo 1000,11,150
servo 1000,12,150
servo 1000,13,150

servo 2000,8,60
servo 2000,9,200
servo 2000,10,60
servo 2000,11,200
servo 2000,12,60
servo 2000,13,200

servo 3000,8,150
servo 3000,9,150
servo 3000,10,150
servo 3000,11,150
servo 3000,12,150
servo 3000,13,150

servo 4000,8,60
servo 4000,9,60
servo 4000,10,60
servo 4000,11,60
servo 4000,12,60
servo 4000,13,60

servo 5000,8,200
servo 5000,9,200
servo 5000,10,200
servo 5000,11,200
servo 5000,12,200
servo 5000,13,200

servo 6000,8,150
servo 6000,9,150
servo 6000,10,150
servo 6000,11,150
servo 6000,12,150
servo 6000,13,150

servo 7500,8,60
servo 7000,9,60
servo 7100,10,60
servo 7200,11,60
servo 7300,12,60
servo 7400,13,60

servo 8000,13,150
servo 8100,12,150
servo 8200,11,150
servo 8300,10,150
servo 8400,9,150
servo 8500,8,150

tloop 8600,1 'goto label 1
end 15000

Monday, May 9, 2011

USB servo board - almost done?

This is looking like the final version of the servo board and includes a number of cool enhancements:

At any point in the script, the user can place a label.
This is marker point from where you can play back sections of an animation.
Users can place GOTO commands in the script, such as "goto 1500ms" (the animation jumps to the point 1.5 seconds into the animation) or "goto label 4". It is this second GOTO command that makes the servo board so useful:



We've also updated the firmware so that one or more of the servo pins can be used as input triggers. Simply tell the board how many input pins you want to use (0-8) and when the appropriate input pin is pulled low, the animation playback jumps to that label number.

For example, pull the first input pin (normally servo 20) low and playback immediately jumps to label 1. Pull the second input pin low (normally servo 19) and playback jumps to label 2. Because our servo pins have ground on the outside and signal on the inner (the middle pin is always 5v) the button in the video simply bridges the two outer pins, to pull the input pin low.

Here's the full script, as used in the video above:

'this is the first animation
'it can also be triggered by sending PORTB.7 low

label 500,1
servo 1000,9,50
servo 1000,10,50
servo 2000,9,220
servo 2000,10,220
servo 3000,9,50
servo 4000,10,50
servo 5000,10,220
servo 6000,9,220
tloop 7000,1000 'go to time point 1000

'this is the second animation loop
'triggered when PORTB.6 goes low

label 10000,2
servo 10000,9,150
servo 10000,10,150
servo 11000,9,220
servo 11000,10,50
lloop 12000,2 'go to label 2

end 15000

Saturday, May 7, 2011

USB servo board update

We're getting close to finishing the 20-channel USB servo controller board.
This latest update has the servos in the correct place on the board (previous versions of the firmware numbered the servos according to the pins/ports they were on, but the PCB layout made them appear to be randomly placed!)

This latest update also includes a surface mount Flash eeprom, rather than an 8-pin DIP. This means that the 8-pin chip appears reversed when the PCB is printed (pin1 is top right, not top left) but when toner-transferred, will appear the right-way around. We had to swap a few pins around on PORTA to simplify the layout for the PCB so a new schematic is included below.



Also to note is that on this board, the SMT memory chip will actually be on the underside (where all the pins are soldered to the copper board).

Servo Usb Smt Eeprom Schema

Servo Usb Smt Eeprom
Print at 100% no scaling in landscape orientation to create your own press-n-peel transfer to make this USB servo controller board with SMT eeprom chip

We're also working on one last final revision of the firmware, to allow the user to place "labels" along the timeline, and to have the servo controller board jump to specific points along the timeline. This will become clearer as screenshots of the software become available....

Friday, May 6, 2011

USB servo board animation playback - edit

One last amendment as the playback routines are written.
All our animations are simply lists of events that happen a specific time after the user has pressed a button (or sent a signal) to start the animation playback.

The PIC keeps a running timer of the time elapsed since playback started, and a list of events and when they need to happen. The list is already sorted into time order (by the host PC before downloading).

The PIC microcontroller simply compares the current time to the time of the next animation in the list. If the current time is greater or equal to the time of the event in the list, it plays out the animation (moves the servo) off the top off the current "stack" of animations, then moves onto the next one.

This approach allows the PIC to catch up with any missed "frames" - in fact this is an important approach, since three things happening at exactly the same time will actually be processed in sequence, one after the other, but very quickly.



Anyway, this leads us to the latest amend:
Timecodes are stored as two-byte values (any number from 0 to 65,535).
At the minute we're storing times as milliseconds from the start. While this is pretty accurate for playback, in reality, we're more likely to want things to move within seconds or half-seconds of each other, not 1/1000th of a second.
If we stick to storing our animation timecodes as milliseconds, the maximum value we can store is 65,535 milliseconds - 65 seconds. The longest animation would be just over a minute long.

By simply storing timecodes as 1/10th seconds (so one second is represented by 10, two seconds by 20 and so on) we can perform animations with timings as low as 1/10th second, but also increase our playback times incredibly.

If the maximum value possible is 65,535 represents 6,535 seconds, this is a massive 108.916 minutes - or 1hr 48min and 55sec of animation!

The software and PIC firmware will be updated shortly with this amendment.
Following the examples given in a previous post, the data written as

servo 500,09,120
servo 500,10,120
servo 2000,09,050
servo 2000,10,200
servo 4000,09,200
servo 5000,10,060
tloop 6000,1000

...is now converted into

0,5,0,9,120 (500 milliseconds = 5 * 1/10th second)
0,5,0,10,120
0,20,0,9,50
0,20,0,10,200
0,40,0,9,200
0,50,0,10,60
0,60,1,0,10

USB servo board animation playback

After a late night at BuildBrighton last night, we finally got the PIC microcontroller talking to the Flash-eeprom. It turns out that the first SMT-to-DIP board wasn't soldered up properly. So after a few hours debugging some code (that eventually turned out to have been working all along) we fixed the dodgy lines and managed to read and write data to/from the Flash device.

So now we need to consider how animations will be stored in memory.
The first, and immediate, use of the Flash memory was to store data in a sequence of 4-byte chunks.

  • The first and second bytes represent the time in milliseconds to have elapsed.
  • The second byte is the servo channel number
  • The third byte is the movement value (where 100=1m/s, 200=2m/s etc)

500,09,120
500,10,120
2000,09,050
2000,10,200
4000,09,200
5000,10,060

We started building an app to allow users to write their animations to the eeprom chip. Then, after a cup of tea and a biscuit, we decided to make a DLL to simplify the whole process, allowing end-users to create their own animation software and integrate it with the servo board. The final solution we came up with (and decided to stick to) was to read a simple text file, made up of the 4-byte chunks, and stream this data over USB to the usb-servo board.

Full details of how the servo board works will be published later (once we've agreed on the communication protocols!) so that other users can contribute their own animation-creation software in future.

After a bit of thought, and trying out a few animations, it became apparent that the eeprom chip has massive amounts of storage which likely to go unused. It also became apparent that most robotic animations are actually repetitions of relatively small animations. For example, walking animations are just cycles of simple, smaller movements (irrespective of the number of legs involved!).

Our final animation decision was to increase the chunk-size to five bytes:

  • First and second bytes are time in milliseconds
  • Third byte is a command byte which changes how the fourth and fifth bytes are interpreted
  • If command byte is "move servo", the fourth byte is the servo number and the fifth byte the movement value
  • If the command byte is "jump to timecode", the internal servo timer is updated to a (two-byte) value represented by bytes four and five


The text file containing these values is updated to an easily-understood format:

servo 500,09,120
servo 500,10,120
servo 2000,09,050
servo 2000,10,200
servo 4000,09,200
servo 5000,10,060
tloop 6000,1000

and these commands are translated into the following byte sequence:

1,244,0,9,120 (500 = highbyte 1, lowbyte 244, third byte=command byte)
1,244,0,10,120
7,208,0,9,50
7,208,0,10,200
15,160,0,9,200
19,136,0,10,60
23,112,1,3,232

The last entry is of particular note.
The command tloop is represented by a 1 in the third byte and in this case means "reset the timer as if it were 1 second after the start of the animation".
As a result, the servo board resets the internal timer, starts at the beginning of the list and reads through the commands, until it hits the appropriate one in the sequence. The result, in this case, is that the last five commands in the list are repeated over and over again.

Wednesday, May 4, 2011

USB servo board first PCB prototype

After a few weeks away, it was nice to get back to Nerd Towers and start etching stuff and messing about with copper boards and solder again.
After lots of development and testing on breadboards, it's finally time to try the usb servo board out for real - here's the first set of etched PCBs for the controller.

We've tried to keep the board as compact as possible, but still allow room for an 8-pin DIP (or one of our spanky new SMT-to-DIP boards) as well as all 20 servo channels.

Phew! That's a lot of holes to drill with a hand-operated push-drill!

How the controller board looks, from the "business side".

Tuesday, May 3, 2011

USB servo board eeprom

The little eeprom chips arrived today. I forgot that they were SMT when I designed the USB servo board for PCB manufacture, so the board has an 8-pin DIP socket, and the eeprom chip is SMT. Bugger!

To get around this, I created a simple SMT-to-DIP converter for 8-pin chips:



The SMT chip goes to the left of the 8-pin DIP connectors. I'll put two rows of 4 x 0.1" header pins where the DIP chip would normally go, effectively turning the SMT chip into an 8-pin DIP.

SMT_to_DIP_8PINPrint at 100% no scaling in landscape orientation to create your own press-n-peel transfer to make this SMT-to-DIP converter

If you're making one of these yourself, note that the PCB design has been mirrored (normally we don't bother mirroring designs, as they are reversed on the bottom of any through-hole mounted board anyway). With this design, however, the copper part of the board will be face up, with the SMT chip soldered onto the copper side (rather than the through-hole components being mounted on the top and soldered underneath).
Because of this, the design is mirrored (but when you use press-n-peel/toner transfer to get the image onto the copper board, it'll end up the right way around).



Dont forget to mount the pin headers on the bottom (non-copper) side of the board, with the shorter legs soldered to the top (copper-side) of the board.

The usb servo board was designed to accommodate either a regular 8-pin DIP or our modified SMT-to-DIP board

Sunday, May 1, 2011

Servo board PCB layout update



Just a quick update on the 20-channel USB servo board with eeprom playback:
this new PCB layout includes the eeprom chip (Atmel's AT45DB041D). Another slight change to the earlier design is that the USB 5v/power supply now goes to the 5V output pin of the regulator rather than the input. This allows the user to connect 4xAA (or 4xAAA) batteries to create a 6V supply or even use a single PP3 (9V) battery to run the device, but safely connect the USB cable at the same time. The original design required the user to disconnect the batteries before connecting the USB cable to download more data to the device. With this new layout, the batteries can safely remain connected and the board still be connected to a PC to download more data.
(a future board with 3.7V rechargeable lipo is in the planning stages but is still some way off!)


Note in this silkscreen and current version of firmware, the servo pin numbering is a little peculiar. This will be addressed in the final version of the firmware!

Monday, April 11, 2011

Working servo board prototype

Here's a quick video and some photos showing the new 20-channel servo board in action! The actual board registers as a HID device. We're including sample code for Windows (but anyone wishing to port the code to Linux/MacOS should be able to do so using something like HIDApi).



The HID device communicates with the host via an 8-byte buffer.
To move the servos, simply set the 7th byte to value 201 (I don't know why we chose that value to represent the "move servo" command, but we did!) and the zero byte to the servo channel number (1-20) and the first byte to the movement value.
The range of valid movement values changes depending on the servo being used.
In theory, the values should be 100-200. This represents a signal range of 1ms to 2ms.



The mid-point should always be 150 (1.5ms) whatever the servo, but we've found that some of our cheap chinese HXT900 servos accept a much wider range (as low as 30, or 0.3ms and as high as 250 or 2.5ms before they start to "chatter" at the end of their range).


Snapshot of simple VB6 app sending data to a generic HID device through an eight-byte wide buffer