Servo does not fully rotate to 0 or 180 degrees

Posted on
  • Hello, I'm fairly new to working with the Espruino Wifi and I love it, however, I'm working on a project using the servo module and am finding that when I send the servo a command like s.move(0); it does not travel as far as when I call it's equivalent s.write(0); on my Particle Photon board. The same goes for s.move(1); it does not travel the full rotation like it does when I call s.write(180); on the Photon. I tried to also call it directly using digitalPulse and found the same results.

    This is causing an issue because I'm losing about 15-20% of the rotation which I need for this project. Is there anyway I could get the servo to go fully to 0 or 180 degrees using the Espruino? Any assistance would be greatly appreciated. Thank you!

  • Glad to hear that you love it [Espruino].

    ...will take a look at it... Seems to me an issue with the pulse length... pulse lengths not covering the full range.

    What do you use as power supply for the servo?

  • Right now, I'm powering the Espruino via the USB and have the servo sharing the ground and powered via a separate 5v power supply like the docs recommend.

    Below is the code I'm using. It's pretty basic. I was just trying to test out the servo module.

    var hat = require('servo').connect(A0);
    var pos=0,t=null;
    
    function sweep(){
      hat.move(pos,500,function(){
        if(pos===0){pos=1;}else{pos=0;}
        t=setTimeout(function(){ sweep(); },1000);
        
      });
    }
    hat.move(0.5);
    sweep();
    
    
  • Ic. Good practice is to put the actions into an onInit() function. To get it going on development time, you add a delayed invocation of it, like this:

    var hat = require('servo').connect(A0);
    var pos=0,t=null;
    function sweep(){
      hat.move(pos,500,function(){
        if(pos===0){pos=1;}else{pos=0;}
        t=setTimeout(function(){ sweep(); },1000);
        
      });
    }
    function onInt() {
      hat.move(0.5, 1000, sweep)
    }
    
    // for convenience while developing:
    setTimeout(onInit, 1000);
    

    Adding the last line simulates a power on with saved code, and you do not have to enter that in the console every time after upload. When you are done with development, the last line is removed just before saving the code.

    That of course does not solve the positioning issue...

  • In the original code there is a contention:

    While the move in line 11 is still going on, you already start with the move in line 4.

  • Hey allObjects, you're right. Thanks! Also you were right about the pulse length. I found if I repeatedly called digitalPulse(A0, 1, 0.2) it would rotate fully clockwise and if I did the same with a time set to 3 instead of 0.2 it would rotate the full amount in the other direction.

    I'm not sure if that will cause a problem but at least I have a starting point now. Thanks for the tip! :)

  • The servo has a maximum speed. If the pulsing stops before the position is reached, the servo stays where where it got the last pulse.

    What I'm a bit surprised that there is no pin initialization. I would expect something like

    pinMode(A0, "output"); A0.reset();
    

    at the beginning. May be it is not needed because the first digitalPulse() takes care of it in its own way. The module works as follows:

    • every 20ms (50 times in a second) a pulse is sent
    • the rising flank of the pulse starts on some servo internal single pulse generator a pulse
    • the servo internal pulse length is defined by the position of the shaft converted into a resistance / voltage divider by a potentiometer which turns with the shaft.
    • for the pulse length differences of the servo internal pulse and the externally applied pulse the servo motor is given power in either forward or reverse direction to close the gap between the pulse lengths.
    • pulses have to be sent until the servo has closed the gap (internal pulse matches externally applied pulse) and with that servo has reached commanded position.

    Therefore, depending on the speed of the servo, it may take one servo more pulses to get to a particular position than another one, and if not given enough pulses at all, the servo never can close the gap... and never gets to the commanded position.

    This is the logic the module applies. Since you can control the time from the outside, you may give not enough time - not enough pulses - and the servo can not 'get there'. In a wrapper around the module invocation you may calculate the minimum time - depending on the position difference and the maximum speed (angle speed = positions per time unit) - you have to 'give' in the move command so that the servo has enough time 'to go there'. As a module builder, I would have anyway an accelerating and decelerating profile with a ramp up, a max speed and a ramp down... or at least a few extra pulses when theoretically having 'arrived' at commanded position. The module calculates the difference but does not apply them when in an E-psilon (Math.) range, at which the difference is considered not existing anymore. When reached that point, a few pulses with the final value would have to be applied.

    With processor we can stop sending pulses - and avoid jitter / unnecessary power consumption. In (old) RC model control, the pulses would keep coming and differences are constantly corrected. This has of course power consumption ramification... and if the pulse length and the internal pulse generation are not highly stable, the servo never comes to rest. It keeps jittering/shivering, which raises serious concerns / power usage.

    *** EDIT / ADDENDUM ***
    More recent / modern servos have now different ways to 'measure' the position / angle of the shaft / arm...

  • Wow, thank you for the detailed description of how servos are controlled as well as the module. You have given me enough to go on and make the adjustments I need to get my servo to sweep the full ~180 degrees. When I get this working I'll post what I have. Thanks!

  • (Serious) Servo manufacturers provide you with the information how much time a sweep takes under different loads and supplied power. That gives you the corner stones for a tight, efficient and fast setup.

  • Hey I just wanted to follow up on my thread here. I created a little servo module that allows me to easily adjust the min and max pulses based on the servo I'm using. This way I get the full 0 - 180 degree sweep. It also has a couple features that I wanted like the ability to actively hold a position as well as the ability to stop the servo mid motion.

    https://github.com/jsrocket/espruino/treĀ­e/master/servoxt

    Hope it helps someone else. :)

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Servo does not fully rotate to 0 or 180 degrees

Posted by Avatar for Ken @Ken

Actions