Shop OBEX P1 Docs P2 Docs Learn Events
Servo.h Library Question — Parallax Forums

Servo.h Library Question

ajwardajward Posts: 1,123
edited 2015-07-05 00:00 in Robotics
After a bit of re-jiggering, I'm trying to get my 4-DOF biped (Scooter) "walking". So far I've had much better luck positioning the servos by programming the PSCU directly with C. The problem I've run into so far is the speed with which the servos move. I've tried setting the ramp speeds at various values, but I'll be darned if I can see much difference. Am i not using ramp_set correctly?My code follows:

[code]
/*

Try to Get Scooter Scooting Around

Started 04 July 2015

*/




#include "servo.h" //include servo.h

#include "simpletools.h" //include simpletools.h




//Define Constants




#define rt_hip 15 //assign right hip servo to pin 15

#define rt_ank 14 //assign right ankle servo to pin 14

#define lt_hip 0 //assign left hip servo to pin 0

#define lt_ank 1 //assign left ankle servo to pin 1




#define rh_ctr 840 //assign right hip servo ~center position

#define ra_ctr 900 //assign right ankle servo~center position

#define lh_ctr 900 //assign left hip servo ~center position

#define la_ctr 900 //assign left hip servo ~center position




#define ramp_set 100 //assign servo ramping speed???




int main() //main function

{

servo_setramp(rt_hip, ramp_set); //set rh ramp value

servo_setramp(rt_ank, ramp_set); //set ra ramp value

servo_setramp(lt_hip, ramp_set); //set lh ramp value

servo_setramp(lt_ank, ramp_set); //set la ramp value



while(1)

{

servo_angle(rt_hip, rh_ctr); //move rh servo to center position

servo_angle(rt_ank, ra_ctr); //move ra servo to center position

servo_angle(lt_hip, lh_ctr); //move lh servo to center position

servo_angle(lt_ank, la_ctr); //move la servo to center position

}

}



[/code} 
Thanks for any wisdom!
Amanda

Comments

  • I take it the old method for inserting code doesn't work now?
    @
  • twm47099twm47099 Posts: 867
    edited 2015-07-05 04:08
    Amanda,
    From the standard servo learn page:

    Servo_setramp(16, 8 ) will slow it down to .8° per 50th of a second. 

    So a value of 100 should move it 10 degrees in 1/50 seconds.

    Are you trying to move the servo quickly or at a slower rate? 

    Set at 8 (0.8 deg in 0.02 sec), the servo will move 90 deg in 2.25 sec
    Set at 100 (10 deg in 0.02 sec), the servo will move 90 deg in 0.18 sec.

    So there can be a significant difference in speed.

    Tom
  • I fixed an earlier mistake in the preceding post.

    Tom

  • I've tried moving them slowly through about 30 degrees. Used various settings from servo_setramp(pin, 1) to servo_setramp(pin, 100) and I just don't see any difference in the servo speed.
    Right now, the servos just seem to snap from position to position... which works. But it looks real clunky. :-(
    Amanda
  • If I did the math correctly... a setramp value of 1 should rotate through 30 degrees in about 6 seconds;
    A value of 1 should become 300 segments and 50 segments per second should take 6 seconds. Eh... no.Thus, I must be doing something wrong with the code.
    Amanda
  • twm47099twm47099 Posts: 867
    edited 2015-08-06 04:23
    Angela,
    The program below is a modification of the program in the simple devices standard servo C-Learning Tutorial.
    I modified it to have 2 different servo ramp settings.  It works when I tested it with a standard servo and an Activity Board.

    (I hope this shows up ok)

    Tom



    /*
      Standard Servo with Ramping.c
    
      Version 0.94 for use with SimpleIDE 9.40 and its Simple Libraries
      
      Moves servo to 0, 90 and 180 degrees.  Uses ramping to gradually move the 
      servo to the target.
      
      learn.parallax.com/propeller-c-tutorials  
    */
    
    #include "simpletools.h"                      // Include simpletools header
    #include "servo.h"                            // Include servo header
    
    int main()                                    // main function
    {
      servo_angle(16, 0);                         // P16 servo to 0 degrees
      pause(500);                                    // Allow 1/2 second to get there
      pause(1000);   
      while(1)
      {                            
      servo_setramp(16, 100);                       // Change by up to 100/10 degree/20 ms 
        servo_angle(16, 1750);                      // P16 servo to 180 degrees
        pause(2000);                                // Allow 2 seconds to get there
                                                    // (with ramping in effect)
    
      servo_setramp(16, 7);                       // Change by up to 7/10 degree/20 ms   
      servo_angle(16, 0);                      // P16 servo to 0 degrees
      pause(6000);                                // Allow 6 seconds to get there
                                                  // (with ramping in effect)
      }
      servo_stop();                               // Stop servo process
    }
    
    
  • Just a quick followup... just got back to working on this project. I should have mentioned that I'm running my servos at 7.2 volts. Would that make a difference?
    Amanda
  • In the C-learning tutorials, Parallax recommends for the ActivityBot to run the high speed CR servos from the 5 cell battery pack (7.5v if using alkaline AA's).  But they also direct that for the Standard Servos that the voltage jumper be set in the 5v position.  I think that you are using standard servos (0 - 180 deg servos).

    Tom

  • In the C-learning tutorials, Parallax recommends for the ActivityBot to run the high speed CR servos from the 5 cell battery pack (7.5v if using alkaline AA's).  But they also direct that for the Standard Servos that the voltage jumper be set in the 5v position.  I think that you are using standard servos (0 - 180 deg servos).

    Tom



    I'm running Bob, my BOE/Activity Bot, with 2-3.7volt LiPo's and that works okay... 'cept for my coding issues. :-)Scooter's brain is the Prop servo control board, so I don't have the 5V/VIN option. Only 6 volt source I have right now would be a 4-AA battery pack. =:-| Maybe I can find a 6 volt SLA for cheap. Battery weight isn't an issue right now since the 'Bot's power comes from an eight foot power cable. Balance is a HUGE problem and adding a battery pack would surely aggravate the problem.
    Amanda
  • Tom,
    I've slightly modified your code and it works... sort of. When going through the "while" the first time, the servo =snaps= to the 120 degree position.  After the first run through, the servo moves nice and slow.But... running this code, the servos are already powered up and manually positioned in their "center" positions. Pressing the reset button results in the same condition... the servo snaps to the 120 position the first cycle and the runs slowly thereafter!???
    /
    
    #include "simpletools.h"                      // Include simpletools header
    
    #include "servo.h"                            // Include servo header
    
    
    
    
    int main()                                    // main function
    
    {
    
         
    
    	while(1)
    
      {    
    
                             
    
    	
    	servo_setramp(15, 7); 	/ Change by up to 7/10 degree/20 ms 
    
    	servo_angle(15, 1200);	                      // P15 servo to ~120 degrees
    
    	pause(6000);	                                // Allow 6 seconds to get there
    
    				// (with ramping in effect)
    
    
    
    
    	servo_setramp(15, 7); 	// Change by up to 7/10 degree/20 ms   
    
    	servo_angle(15, 800); 	// P15 servo to ~80 degrees
    
    	pause(6000);	// Allow 6 seconds to get there
    				// (with ramping in effect)
    
    
    
                                                  
    
    	servo_setramp(15, 7); 	// Change by up to 7/10 degree/20 ms   
    
    	servo_angle(15, 400); 	// P15 servo to ~40 degrees
    
    	pause(6000); 	// Allow 6 seconds to get there
    
    				// (with ramping in effect)                                            
    
      
    
      }
    
      
    
    	servo_stop(); 	// Stop servo process
    
      
    
    }
    
    




  • Okay, more tinkering and I found that each servo reacts to its first command by moving at full speed!??? Don't understand this bit either.
    Anywho, my workaround/kludge is to position Scooter with all his servos at the desired starting positions, then send commands to each one to move to that position with an initialization function. Seems an odd way to have to do this, but it works.
    @
  • twm47099twm47099 Posts: 867
    edited 2015-07-31 19:29
    Amanda,
    I think I see what the problem is in the servo library.  In the servo.c file before servo_ramp can have an effect, an array "p[14]" has to be initialized with the servo pin number.  For example for the first servo used p[0] has to be set to the pin number of the first servo.

    Unfortunately, the only library function that does that is servo_set() which is called by servo_angle() and servo_speed().  servo_set() also sets the pulse width in the array that is used to send the pulse.

    Until servo_set() populates the p array with the pin numbers and servo_ramp is called, the servo step size array is set to 2000 for each element -- high speed.

    All of the variables in the functions are static, which means you can't change them from outside the file where they are declared, otherwise it would be easy to either change the initial step sizes or initialize the pin array from your program.

    You could change them in the servo.c file, but then you would have to rebuild the library and would end up with a non-standard library (probably not a good idea). 

    It probably could be changed so that if there was no initial ramp command it would use the normal array, but if ramp was called before p[] was initialized with the pin number, that the step size array value for that pin number could be initialized to a desired step number.  Or just add the code from servo_set that tests for the pin or defines the element in the p array with the pin number to the servo_ramp function and rebuild the library.  Regardless you would have to make sure that it didn't affect other functions, and that any other functions that used servos didn't screw things up.  Also since the library would be non-std other users wouldn't be able to use your code.

    It might be fun to try, but could easily end up a mess.

    Tom
  • It might be fun to try, but could easily end up a mess.

    Tom


    Now we're talking. If there's one thing I excel at it's messing things up! :-)@
  • Okay... I've no idea how to rebuild a library which I would, otherwise, have no qualms about doing.

    I've looked at the servo.c file and started wondering... Right now, I'm only using two of the functions, so can I just pull out the appropriate sections of code and use them directly in my project?
  • twm47099twm47099 Posts: 867
    edited 2015-08-06 04:21
    ajward wrote: »
    Okay... I've no idea how to rebuild a library which I would, otherwise, have no qualms about doing.

    I've looked at the servo.c file and started wondering... Right now, I'm only using two of the functions, so can I just pull out the appropriate sections of code and use them directly in my project?

    I built a fast SPI interface library using the C-Learn tutorial here:
    http://learn.parallax.com/propeller-c-library-studies

    The tutorial is pretty basic, but it is a good cookbook. Since the servo library already exists, all that is necessary is to change the servo.c file (the servo_setramp function) and recompile (see the tutorial for the settings to use in the project view).

    The way to do this is:
    (I recommend copying the existing servo library folder to a separate folder name in case you have to restore it.)

    1. Open SimpleIDE.
    2. Click on the open project icon.
    3. Navigate to the folder "SimpleIDE\Learn\Simple Libraries\Motor\libservo"
    4. Click on and open "libservo.side"
    5. Click on the project manager icon in the lower left corner of the IDE window
    6. In the project manager window, double click on "servo.c"
    That will open a second tab (servo.c) in the IDE screen
    7. Make your changes to the function.
    8. In the project manager window at the bottom click on the "linker" tab and make sure that the "create project library" box is checked.
    9. Make sure that in the "Project Options" tab the memory model you are using is selected (you should build at least 2 times, once for CMM and again for LMM)
    10. Click the hammer icon at the top of the IDE screen -- that will build the library with the memory model you selected in step 9.


    I would be careful about just pulling the 2 functions because there are usually some other dependencies in other files in the library, particularly the .h file.

    Tom
  • More questions...

    Alrighty! After my second cup of coffee, I modified the servo.c file and (re)built the library. I checked the cmm folder and, lo and behold, there was a shiny new libservo.a file. However the file had some friends... libservo.binary, libservo.elf and servo.o. These don't appear in the untouched cmm folder. Thus the questions:
    1. Did I do something wrong?
    2. Are these files normal?
    3. What are they used for?

    Thanks for any wisdom!!!!

    Amanda
  • ajward wrote: »
    More questions...

    Alrighty! After my second cup of coffee, I modified the servo.c file and (re)built the library. I checked the cmm folder and, lo and behold, there was a shiny new libservo.a file. However the file had some friends... libservo.binary, libservo.elf and servo.o. These don't appear in the untouched cmm folder. Thus the questions:
    1. Did I do something wrong?
    2. Are these files normal?
    3. What are they used for?

    Thanks for any wisdom!!!!

    Amanda

    Amanda,
    I get those file types when I make a library. I'm not sure if they are needed, but I've never messed with them.

    In the tutorial it says that you should get a ".o" file, but when I check the standard SimpleIDE libraries I also see just an ".a" file. Not sure what is different about the distribution libraries??

    In the spi library I made I had a general spi file and I put code for different devices (MCP3208, DS1620, MMA7455, and SCP1000) in their own files. When I compiled the primary file (libspiasm.side), I had all the other c files and the h file in project manager window. Compiling generated the following:

    cmm%20directory.jpg

    Did you get a chance to try using the new library to see if it works the way you want?

    Tom
    417 x 197 - 24K
  • twm47099twm47099 Posts: 867
    edited 2015-08-16 21:45
    twm47099 wrote: »
    Amanda,
    I think I see what the problem is in the servo library.  In the servo.c file before servo_ramp can have an effect, an array "p[14]" has to be initialized with the servo pin number.  .... <<twm 8/16 -- wrong see below>>

    Until servo_set() populates the p array with the pin numbers and servo_ramp is called, the servo step size array is set to 2000 for each element -- high speed.

    All of the variables in the functions are static, which means you can't change them from outside the file where they are declared, otherwise it would be easy to either change the initial step sizes or initialize the pin array from your program.

    You could change them in the servo.c file, but then you would have to rebuild the library and would end up with a non-standard library (probably not a good idea).  .... <<twm 8/16 -- didn't work see below>>

    It probably could be changed so that if there was no initial ramp command it would use the normal array, but if ramp was called before p[] was initialized with the pin number, that the step size array value for that pin number could be initialized to a desired step number.  Or just add the code from servo_set that tests for the pin or defines the element in the p array with the pin number to the servo_ramp function and rebuild the library.  ...

    It might be fun to try, but could easily end up a mess. ...<<wm-8/16 fun but not effective -- see below>>

    Tom

    Well I tried it and it didn't work. I tried changing the servo_ramp code to initialize the step size array element even if servo_ramp was the first function called. When that didn't work I just tried setting a small step size in the elements in declaration statement. That also didn't work. (I had added a print statement in the servo.c file so that I could see if the revised version of the library was being used -- it was-- and if the step size variable had been properly set -- it was.)

    Looking at the servo function in the library and the pulse generation function I think that the issue is that the ramp step size is used as a delta between the current position (pulse) and the final commanded position (pulse). Since there is no position feedback from the servo to the propeller, the first time it is called the function has no way of knowing what the starting value of the pulse is for the current position to add (or subtract) the delta from, so it just sends the pulse for the final position, and it goes full speed. Once that initial pulse has been sent, the function has a known value to start from, so servo_ramp works.

    So unfortunately, without having some method of telling the propeller the initial servo position (a pot for example) and writing some code for the function to make use of that, I think that your method of pre-positioning the servos may be the way.

    Tom
Sign In or Register to comment.