Error when trying to drive 360° servo

Posted on
  • I just tried to drive an SG90 Micro Servo with 360° gear from an Original Espruino, wired to pin C7 (as the example suggests) - { range:2 } was the outcome of another test with an "ordinary" SG90.

    var Servo = require('servo').connect(C7, { range:2 });
    
    let Count = 0;
    
    function move () {
      if (Count < 10) {
        Count++;
        Servo.move(1, move);
      }
    }
    move();
    

    However, when uploading this code from the Web IDE it leads to an endless loop of error messages (and finally crashes the Chrome browser):

    Uncaught Error: Pulse Time given for digitalPulse is less than 0, or not a number
     at line 1 col 87
    ...Pulse(l,1,g+E.clip(b,0,1)*e);c+=1E3/(20*f)
                                   ^
    in function called from system
    ...
    

    Does this code try to recursively call Servo.move rather than my function move? But why does it then lead to an endless loop?

    Amendment: renaming my function move to moveServo still loops endlessly

  • I think likely what happens is the digitalPulse in servo causes an exception which stops the next command executing which in turn causes the interval to keep on being called.

    Unminified source is at : http://www.espruino.com/modules/servo.js

    Is that literally all the code you have there? because I'd only expect that error if you were calling move with something outside the 0..1 range

  • indeed, that's all my code - I just wanted to "quickly" test a servo (but nothing works quickly if I am touching it - I tend to break everything)

    Amendment: I also just checked the firmware state (just to be sure): and, yes, it is 2v10

    Amendment 2: just to be sure, I flashed 2v10 one more time and tried my code again - with the same result.

  • I just looked into the code you referenced - and I found a potential problem:

            if (callback) callback();
    

    Shouldn't you always return callback()?

    Amendment: I found the mistake - if a callback is given, time must be specified as well, otherwise the callback function is taken as the time argument.

    If you like, you may change the beginning of your move function like so:

      return {move:function(pos, time, callback) {
        if (typeof time === 'function') {
          callback = time; time = undefined;
        }
        if (typeof time !== 'number') time = 1000;
    

    At least, you should protect the time argument better (an error message would be fine, but you may not have enough resources on the device for such an approach)

  • I changed your code a bit, and now everything works as foreseen. Here is my complete test

    //var Servo = require('servo').connect(C7, { range:2 });
    
    
    function Servo_connect (pin,options) {
      var interval, currentPos;
      var offs = 1, mul = 1;
      if (options && options.range) {
        mul = options.range;
        offs = 1.5-(mul/2);
      }
    
      return {move:function(pos, time, callback) {
        if (typeof time === 'function') {
          callback = time; time = undefined;
        }
        if (typeof time !== 'number') time = 1000;
        
        var amt = 0;
        if (currentPos===undefined) currentPos = pos;
        if (interval)
          clearInterval(interval);
        var initial = currentPos;
        interval = setInterval(function() {
          currentPos = pos*amt + initial*(1-amt);
          digitalPulse(pin, 1, offs+E.clip(currentPos,0,1)*mul);
    
          if (amt >= 1) {
            clearInterval(interval);
            interval = undefined;
            if (callback) callback();
            return;
          } else {
            amt += 1000.0 / (20*time);
          }
        }, 20);
      }};
    }
    
    
    let Servo = Servo_connect(C7, { range:2 });
    
    let Count = 0;
    function move () {
      if (Count < 10) {
        Count++;
    print('Count: ' + Count);
        Servo.move(1, 1000, move);
      }
    }
    move();
    

    Since you clearInterval, an explicit return is not necessary, but it may be a good idea to restrict time to values > 0 in order to avoid a division by zero (or negative values)

  • Sorry - missed this! So it did work ok, but it was just the usage of move?

    The typeof time check sounds good to me - I'll get those changes in

  • Well, the primary problem was that I passed my callback as the second argument - where you expect a time. And because of a proper check I did not immediately find the mistake.

    move worked as intended - the endless loop was a side-effect of the wrong time argument.

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

Error when trying to drive 360° servo

Posted by Avatar for Andreas_Rozek @Andreas_Rozek

Actions