User avatar
joan
Posts: 14088
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Driving multiple servos from the RaspberryPi

Sun Feb 10, 2013 9:52 am

Forris wrote:...
As an example, looking at Joan's original video of controlling multiple servos shows them rotating smoothly - is this just a better quality servo?
More through luck than judgement. The video you're referring to probably predates servoblaster. I can't remember if that was C in userland, or a kernel process I had developed at the time called mygpio. I abandoned mygpio as Richard's solution was much better. I only have cheap servos. As the previous poster said any smoothness would be down to regular updates.

Forris
Raspberry Pi Certified Educator
Raspberry Pi Certified Educator
Posts: 279
Joined: Fri Jan 06, 2012 7:46 pm

Re: Driving multiple servos from the RaspberryPi

Sun Feb 10, 2013 7:49 pm

Thanks for the tips (and the honesty, Joan). So, time to improve the coding skills then !

Charlienofun
Posts: 1
Joined: Sun Feb 10, 2013 11:16 pm

Re: Driving multiple servos from the RaspberryPi

Sun Feb 10, 2013 11:26 pm

Would it be possible to generate a "multiplexed" signal?

I'd like to connect to a RC transmitter that expects the PPM signal which is all 8 servo channels sent over one wire with a pause after the 8th channel. I was hoping it was possible since the Pi has one PWM pin.

User avatar
rurwin
Forum Moderator
Forum Moderator
Posts: 4258
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

Re: Driving multiple servos from the RaspberryPi

Mon Feb 11, 2013 8:56 am

Worked first time, just like it said in the readme. Very nice.

Do you have any plans to prompt the official RaspPi kernel to add this to their build? I'm sure doing a rebuild every time there is a new kernel is going to get old very fast.

rgh
Posts: 211
Joined: Fri Nov 25, 2011 3:53 pm

Re: Driving multiple servos from the RaspberryPi

Sat Feb 16, 2013 8:30 am

rurwin wrote:Worked first time, just like it said in the readme. Very nice.

Do you have any plans to prompt the official RaspPi kernel to add this to their build? I'm sure doing a rebuild every time there is a new kernel is going to get old very fast.
Thanks. The new servod implementation is a simple user space process, so is independent of the kernel version. I don't currently see any advantage in the original kernel module approach so couldn't justify trying to get it added to the official kernel.

rgh
Posts: 211
Joined: Fri Nov 25, 2011 3:53 pm

Re: Driving multiple servos from the RaspberryPi

Sat Feb 16, 2013 8:40 am

Charlienofun wrote:Would it be possible to generate a "multiplexed" signal?

I'd like to connect to a RC transmitter that expects the PPM signal which is all 8 servo channels sent over one wire with a pause after the 8th channel. I was hoping it was possible since the Pi has one PWM pin.
Yes, I think that would be quite straightforward. Can you give us an idea of what sort of timing you need? For example, what is time between the start of one pulse and the next, how long is the pause after the 8th pulse, etc?

mikkov
Posts: 2
Joined: Tue Feb 19, 2013 2:57 pm

Re: Driving multiple servos from the RaspberryPi

Tue Feb 19, 2013 3:02 pm

Servoblaster userland seems to be the best way to control servos with pi.

I have everything working except one small thing. I happen to have inverting buffer between gpio and servo, so I would need to invert the output signal. I have to admit that I have some problems understanding the internals of servod, so how to invert the output?

mikkov
Posts: 2
Joined: Tue Feb 19, 2013 2:57 pm

Re: Driving multiple servos from the RaspberryPi

Tue Feb 19, 2013 6:42 pm

mikkov wrote:Servoblaster userland seems to be the best way to control servos with pi.

I have everything working except one small thing. I happen to have inverting buffer between gpio and servo, so I would need to invert the output signal. I have to admit that I have some problems understanding the internals of servod, so how to invert the output?
OK, this seems to do it for me

Code: Select all

diff --git a/ServoBlaster/servod.c b/ServoBlaster/servod.c
index d22ed0f..9404e55 100644
--- a/ServoBlaster/servod.c
+++ b/ServoBlaster/servod.c
@@ -259,12 +259,12 @@ set_servo(int servo, int width)
        dp[width] = mask;

        if (width == 0) {
-               cbp->dst = phys_gpclr0;
+               cbp->dst = phys_gpset0;
        } else {
                for (i = width - 1; i > 0; i--)
                        dp[i] = 0;
                dp[0] = mask;
-               cbp->dst = phys_gpset0;
+               cbp->dst = phys_gpclr0;
        }
 }

@@ -327,6 +327,7 @@ init_ctrl_data(void)
        dma_cb_t *cbp = ctl->cb;
        uint32_t phys_fifo_addr;
        uint32_t phys_gpclr0 = 0x7e200000 + 0x28;
+       uint32_t phys_gpset0 = 0x7e200000 + 0x1c;
        int servo, i;

        if (delay_hw == DELAY_VIA_PWM)
@@ -343,7 +344,7 @@ init_ctrl_data(void)
        for (i = 0; i < NUM_SAMPLES; i++) {
                cbp->info = DMA_NO_WIDE_BURSTS | DMA_WAIT_RESP;
                cbp->src = mem_virt_to_phys(ctl->sample + i);
-               cbp->dst = phys_gpclr0;
+               cbp->dst = phys_gpset0;
                cbp->length = 4;
                cbp->stride = 0;
                cbp->next = mem_virt_to_phys(cbp + 1);

rgh
Posts: 211
Joined: Fri Nov 25, 2011 3:53 pm

Re: Driving multiple servos from the RaspberryPi

Tue Feb 19, 2013 6:58 pm

@mikkov: That looks about right to me; I must get round to adding an option to invert outputs. You are not the first that has wanted it.

Fr4gg0r
Posts: 15
Joined: Tue Mar 26, 2013 1:15 am

Re: Driving multiple servos from the RaspberryPi

Tue Mar 26, 2013 1:17 am

Hi,
how would you recommend accessing your servod driver from C?

rgh
Posts: 211
Joined: Fri Nov 25, 2011 3:53 pm

Re: Driving multiple servos from the RaspberryPi

Tue Mar 26, 2013 9:10 am

Fr4gg0r wrote:Hi,
how would you recommend accessing your servod driver from C?
I use something like this:

Code: Select all

static void
set(int servo, int position)
{
	char buf[32];
	int fd;

	sprintf(buf, "%d=%d\n", servo, position);

	if ((fd = open("/dev/servoblaster", O_WRONLY)) >= 0) {
		int n = strlen(buf);
		if (write(fd, buf, n) != n)
			fprintf(stderr, "Failed to set %s: %s\n", buf, strerror(errno));
		close(fd);
	} else {
		fprintf(stderr, "Failed to open servoblaster\n");
	}
}

User avatar
recantha2
Posts: 277
Joined: Wed Nov 14, 2012 9:34 am
Location: Potton, Bedfordshire
Contact: Website

Re: Driving multiple servos from the RaspberryPi

Fri Apr 05, 2013 6:49 am

Thanks for this great thread - ServoBlaster is now driving a servo from my Pi and controlling the position of a camera module :-) I didn't manage to get the userland working but the kernel one works fine.
--
Michael Horne - @recantha
Raspberry Pi blog - http://www.recantha.co.uk/blog

Cambridge Raspberry Jam
Website: http://camjam.me
Facebook: https://www.facebook.com/cambridgeraspberryjam
Follow the Cambridge Raspberry Jam on Twitter - @cambridgejam

mikerr
Posts: 2770
Joined: Thu Jan 12, 2012 12:46 pm
Location: UK
Contact: Website

Re: Driving multiple servos from the RaspberryPi

Sat Apr 13, 2013 5:32 pm

Not seen any python code in this thread ?

Quick and dirty example in python driving some 360 degree continuous servos:

Code: Select all

from subprocess import call
from time import sleep

while True:
        call (["echo 1=200 > /dev/servoblaster"], shell=True)
        call (["echo 2=100 > /dev/servoblaster"], shell=True)
        sleep(1)
        call (["echo 1=200 > /dev/servoblaster"], shell=True)
        call (["echo 2=200 > /dev/servoblaster"], shell=True)
        sleep(1.5)
        call (["echo 1=100 > /dev/servoblaster"], shell=True)
        call (["echo 2=200 > /dev/servoblaster"], shell=True)
        sleep(1)
        call (["echo 1=100 > /dev/servoblaster"], shell=True)
        call (["echo 2=100 > /dev/servoblaster"], shell=True)
        sleep(1.5)
        call (["echo 1=100 > /dev/servoblaster"], shell=True)
        call (["echo 2=200 > /dev/servoblaster"], shell=True)
        sleep(1)
        call (["echo 1=151 > /dev/servoblaster"], shell=True)
        call (["echo 2=149 > /dev/servoblaster"], shell=True)
        sleep(2)

Continuous rotation servos are stopped at 150 (or close to), clockwise at more than that (200), anticlockwise at less than that(100).

In action here: https://www.youtube.com/watch?v=HdCb-Lcx9Qw
Android app - Raspi Card Imager - download and image SD cards - No PC required !

olaftrn
Posts: 2
Joined: Mon Apr 15, 2013 8:23 am

+5V problem on Pi

Mon Apr 15, 2013 8:44 am

Hi!
The idea is Great. It's Nice!
My english is not so good I do not
understand the +5V problem well.
The pins have +3.3V output I know that.
Is that correct I have to check the
current on the pin? Not more than 16mA?
Thank You!
Must I recompile the kernel? My wheezy is
from the Feb 2013.

adentse
Posts: 7
Joined: Thu Nov 15, 2012 11:33 pm

Re: Driving multiple servos from the RaspberryPi

Mon May 06, 2013 10:39 am

I made a batch of 10 convenient break out board for thoose servos, as I wrote earlier in this thread.

Image´

It has a buffer IC to make the signals 5V, and it has the serial port broken out, and the complete RPi GPIO port is passed through.

They are just wasting space on my desk now :) Would $10 for one be to much?

Best regards
Mikael

rgh
Posts: 211
Joined: Fri Nov 25, 2011 3:53 pm

Re: Driving multiple servos from the RaspberryPi

Sun Sep 01, 2013 2:08 pm

I just pushed an update to https://github.com/richardghirst/PiBits ... rvoBlaster, which:
  • Adds an option to servod to automatically turn off servo pulses some time after the last update (e.g. "sudo ./servod --idle-timeout=2000" will turn off pulses after 2000ms, or 2 seconds).
  • Fixes servod to use GPIO-21 for Rev 1 boards and GPIO-27 for Rev 2 boards, so that it does not interfere with the camera module. Not tested on Rev 2, as I don't have one.
  • Added a "make install" option for servod for those who want it started automatically on system startup.
  • Reorganised the source to separate the user and kernel space implementations.
  • Added "make uninstall" options for both servod and servoblaster.ko.
The user space implementation, servod, is the preferred one, and you should not normally be concerned with the servoblaster.ko kernel module any more.

mikerr
Posts: 2770
Joined: Thu Jan 12, 2012 12:46 pm
Location: UK
Contact: Website

Re: Driving multiple servos from the RaspberryPi

Sun Sep 01, 2013 3:16 pm

Good stuff, will try later (I have rev1 and rev2 Pi's)

The timeout is welcome, my servos get warm just idling for some reason
and I didn't initially realise servod kept them powered unless you sent a '0'.

rgh
Posts: 211
Joined: Fri Nov 25, 2011 3:53 pm

Re: Driving multiple servos from the RaspberryPi

Wed Sep 11, 2013 9:19 pm

I pushed another servod.c update to github at https://github.com/richardghirst/PiBits ... rvoBlaster.

ServoBlaster will now drive up to 21 servos (or 17 on a Rev 1 board), rather than just 8.

It will also now let you specify pulse widths from 0 to 20ms (20ms is the cycle time, so that is the equivalent of always-on). This is very useful for driving things other than servos with a PWM signal. For example, you can now use ServoBlaster to control the brightness of up to 21 LEDs.

Command line options have also been added to invert the output polarity, and to specify which header pins you want ServoBlaster to control. Please see the README for details.

Reports from anyone trying this on a Rev 2 board are welcome, as I only have Rev 1 here (thanks in advance, mikerr ;-))

For anyone interested in the low level detail, I also fixed a bug in this version which meant pulse width changes were not necessarily applied to the output immediately. This was not obvious driving servos, but when switching LEDs between low and high brightness I could see that sometimes the transition happened in two or three steps over some small fraction of a second, rather than all at once. This seems to have been down to updates from the CPU being cached and not immediately visible to the DMA controller. I think I've solved that by making CPU and DMA controller both use the L2 cache coherent (non-allocating) mapping, or "alias 4" in the BCM2835 Peripherals documentation.

User avatar
clicky
Posts: 306
Joined: Thu Oct 25, 2012 7:34 am

Re: Driving multiple servos from the RaspberryPi

Thu Sep 12, 2013 7:23 am

I was just to finish pi4j implementation that uses your servo driver so could you please help me with something:

In this latest version you can specify pins in a list - would it be too hard to provide a way for such list to be read back somehow? Maybe as a comment at the end of read from /dev/servoblaster device?

Not so sure if, maybe, could control on /dev/servoblaster use pin numbers instead of numbers 0-7? That way it would be more straight forward where servo is really attached to :) Using nice adentse's servo adapter I had to guess did I connect servo to 'first' or 'last' pin.

rgh
Posts: 211
Joined: Fri Nov 25, 2011 3:53 pm

Re: Driving multiple servos from the RaspberryPi

Thu Sep 12, 2013 7:42 pm

You can in fact map the servo numbers to the P1 header pins already. In this example I have four servos connected to P1 pins 7, 11, 12, and 15, and I refer to them as servos 7, 11, 12 and 15 when writing to /dev/servoblaster:

Code: Select all

[email protected] ~ $ sudo ./servod --p1pins=0,0,0,0,0,0,0,7,0,0,0,11,12,0,0,15

Board revision:              1
Using hardware:            PWM
Idle timeout:         Disabled
Number of servos:            4
Servo cycle time:        20000us
Pulse width units:          10us
Minimum width value:        50 (500us)
Maximum width value:       250 (2500us)
Output levels:          Normal

Using P1 pins:           0,0,0,0,0,0,0,7,0,0,0,11,12,0,0,15

Servo mapping:
     7 on P1-7           GPIO-4
    11 on P1-11          GPIO-17
    12 on P1-12          GPIO-18
    15 on P1-15          GPIO-22
Beware that servo IDs run from 0, and P1 pins run from 1, so there is one more '0' than you might expect in that p1pins string.
In fact, the code I pushed yesterday would only let you do that up to servo ID 20; I've just pushed a minor update to let you use servo IDs up to 31.

So far as being able to query the pin list, I could create a /dev/servoconfig or similar that you could read. What format data would you want in that file? It needs to cover P1 and P5 header pins, and which servo IDs their pins map to. I suppose the obvious solution is to just write the active --p1pins and --p5pins parameters to the file, then you'd have to parse them. If you did not specify any parameters, it'd write the default values to the file. Would that work for you?

User avatar
clicky
Posts: 306
Joined: Thu Oct 25, 2012 7:34 am

Re: Driving multiple servos from the RaspberryPi

Sat Sep 14, 2013 9:47 am

rgh wrote:You can in fact map the servo numbers to the P1 header pins already. In this example I have four servos connected to P1 pins 7, 11, 12, and 15, and I refer to them as servos 7, 11, 12 and 15 when writing to /dev/servoblaster:

Code: Select all

[email protected] ~ $ sudo ./servod --p1pins=0,0,0,0,0,0,0,7,0,0,0,11,12,0,0,15

Board revision:              1
Using hardware:            PWM
Idle timeout:         Disabled
Number of servos:            4
Servo cycle time:        20000us
Pulse width units:          10us
Minimum width value:        50 (500us)
Maximum width value:       250 (2500us)
Output levels:          Normal

Using P1 pins:           0,0,0,0,0,0,0,7,0,0,0,11,12,0,0,15

Servo mapping:
     7 on P1-7           GPIO-4
    11 on P1-11          GPIO-17
    12 on P1-12          GPIO-18
    15 on P1-15          GPIO-22
Beware that servo IDs run from 0, and P1 pins run from 1, so there is one more '0' than you might expect in that p1pins string.
In fact, the code I pushed yesterday would only let you do that up to servo ID 20; I've just pushed a minor update to let you use servo IDs up to 31.
I see what you mean. That would, kind of, a assumed, special pin list defined in configuration of servod for that kind of simple mapping to work. On the other hand, your code has all the information needed for mapping to be seamless on the fly - but it just need to be exposed somehow.

What if I propose a different approach to you as alternative referencing servos with number from 0 to max number of defined servos in the list with referencing servo in your driver with a pin name?
rgh wrote:So far as being able to query the pin list, I could create a /dev/servoconfig or similar that you could read. What format data would you want in that file? It needs to cover P1 and P5 header pins, and which servo IDs their pins map to. I suppose the obvious solution is to just write the active --p1pins and --p5pins parameters to the file, then you'd have to parse them. If you did not specify any parameters, it'd write the default values to the file. Would that work for you?
That would be good solution, too. It really doesn't matter how we obtain 'reference' to a servo as long it works without issues.

My above suggestion would be appropriate only if mapping a pin name (in format Px.y) is deemed fast enough for the purpose of the driver. I understand that number 0-n is direct reference to the array you hold internally, and that passing an index is much quicker than using an map instead. And some usages of the driver would require writing new value of a quite a few servos up to 333 times a second (if/when driver allows/will allow that and someone wanted to use fast digital servos for fine adjustments - like tail servo on a RC helicopter). At the moment I have no real 'feel' what would such requirement be in real terms of a RPi CPU.

So, your suggestion of having extra device where such mapping can be read from works as well from my perspective even though from 'neatness' angle alternative of Px.y=value would look better.

- - - - - -

Slightly different question about your driver: would it allow sending more servo 'commands' in format n=value in through same file handle (file stream from Java perspective) with '\n' at the end or each time new file needs to be opened each time? (apologies for not being able to test it yet/check your c code for the answer)

rgh
Posts: 211
Joined: Fri Nov 25, 2011 3:53 pm

Re: Driving multiple servos from the RaspberryPi

Thu Sep 19, 2013 9:00 am

Note the driver needs to know which pins are to be used for servos, so it can program them as outputs on startup. So, if you want to use a P1-4=<width> sort of syntax "'P1-4" would only be valid if either P1-4 was one of the default pins, or if you'd specified it in a --p1-pins= parameter.

Anyway, it'd be easy enough to support a P1-4=<width> syntax in addition to the current syntax, and I can see that might be useful, so I'll add it. Not until sometime next week though.

Your other question, about opening the device file once and then writing multiple commands -- that should work ok.

You also mentioned doing updates up to 333 times a second. This driver uses a 20ms cycle time for the servo pulses, so there is really no point updating the pulse width more often than every 20ms (i.e. 50 times a second). It could be changed to use a shorter cycle time if someone needed it.

User avatar
clicky
Posts: 306
Joined: Thu Oct 25, 2012 7:34 am

Re: Driving multiple servos from the RaspberryPi

Thu Sep 19, 2013 9:22 am

rgh wrote:Note the driver needs to know which pins are to be used for servos, so it can program them as outputs on startup. So, if you want to use a P1-4=<width> sort of syntax "'P1-4" would only be valid if either P1-4 was one of the default pins, or if you'd specified it in a --p1-pins= parameter.
Yes. I am aware of it and it makes sense. That's why a separate device which can be read which returns list in that format (or some other mechanism we discussed here) would be useful. If you try a pin that is not configured and got error that would be completely expected.

Now, just a food for thoughts: what if you can configure it 'on the fly' adding new pins as someone tried unconfigured pin for the first time? Also, you might, then want a format of P1-4=<something special> to deconfigure pin if not in use any more.

No idea how hard would that be - but if possible would make /dev/servoblaster really easy to be used and remove some static (or semi-static) constraints. And I hope you don't mind my 'daydreaming' here! :) Again - I am aware that such operation itself can be slightly costlier and could cause all other servos to 'lose' a few pulses while 're-configuration' is happening.
rgh wrote:Anyway, it'd be easy enough to support a P1-4=<width> syntax in addition to the current syntax, and I can see that might be useful, so I'll add it. Not until sometime next week though.
Thanks! :)
rgh wrote:Your other question, about opening the device file once and then writing multiple commands -- that should work ok.
Thanks again. I'll organise our code to be based on file being constantly open.
rgh wrote:You also mentioned doing updates up to 333 times a second. This driver uses a 20ms cycle time for the servo pulses, so there is really no point updating the pulse width more often than every 20ms (i.e. 50 times a second). It could be changed to use a shorter cycle time if someone needed it.
That's fine. I expected that behaviour. But if you eventually make cycle shorter (for all pins at the same time - I expect that to be cheaper - or each individual pin) it would help.

Again - this is only my thinking ahead - a day dreaming - all singing and dancing final driver would, in that case, have ability of setting each pins frequency to 50Hz, 65Hz, 120Hz, 240Hz, 333Hz (or something like that) - or even better almost free form from 0Hz to 333Hz and you would be able (with some constraints) to change resolution between 1us to 10us... (that last one is a bit stretched I know! O : ). Now I do understand that there are trade offs in such cases and that's why I didn't even begin to contemplate asking you (or looking into it myself) for such concessions.

Even with all we already have - Servo Blaster presents really cool piece of software! Thank you! :)

rgh
Posts: 211
Joined: Fri Nov 25, 2011 3:53 pm

Re: Driving multiple servos from the RaspberryPi

Sun Sep 29, 2013 3:30 pm

Further updates, as requested by clicky :-)

As an alternative command syntax you can now specify header pins rather than servo numbers when writing to /dev/servoblaster. For example, if you have a servo connected to P1 pin 16, you could set it to mid position with "echo P1-16=150 > /dev/servoblaster". This presupposes that servoblaster has been told to use P1-16 as a servo control output (P1-16 is one of the default outputs, so no explicit command line option is needed for this example).

Also a file /dev/servoblaster-cfg is created, which can be read to discover which pins servoblaster has been configured to use. If you are parsing that file please note that the first two lines may appear in either order, depending on what order the --p1pins and --p5pins command line options have been specified.


Richard

User avatar
clicky
Posts: 306
Joined: Thu Oct 25, 2012 7:34 am

Re: Driving multiple servos from the RaspberryPi

Mon Sep 30, 2013 8:28 pm

Fantastic! Thanks!

I'll be adding all needed changes to pi4j now!

BTW quick question: is it going to be possible to read /dev/servoblaster of userspace implementation?

Return to “Automation, sensing and robotics”