Go Down

Topic: Different Servo situation, but same odd jitters (Read 135 times) previous topic - next topic

kjmclark

I've read a dozen or so requests for help with servos, and I think this problem is a bit different.  But someone made the comment on one of those threads that calls to Serial will cause problems, and I wonder if that's part of what I'm seeing.  I've attached a Sparkfun TFMini to the horns of a Futaba S3003 servo.  I'm only using one motor.  I'm trying to make a poor-man's LIDAR system, with a +50º to -50º, slow, smooth sweep.  What I'm getting is a smooth sweep about 80% of the time, and jerky, twitchy behavior 20% of the time.

Code is:
Code: [Select]
/*
 *  Testbed for integrating servo sweep with TFMini
*/

#include <Servo.h>
#include <SoftwareSerial.h>
#include "TFMini.h"

// Setup software serial port
SoftwareSerial mySerial(2, 3);      // Uno RX (TFMINI TX), Uno TX (TFMINI RX)
TFMini tfmini;
 
Servo myservo;  // create servo object to control a servo
                // twelve servo objects can be created on most boards
 
int pos = 0;    // variable to store the servo position
 
void setup()
{
  Serial.begin(19200) ;
 
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  while (!Serial){
  }
 
  mySerial.begin(TFMINI_BAUDRATE);

  // Step 3: Initialize the TF Mini sensor
  tfmini.begin(&mySerial);   
}
 
void loop()
{
  int val = 0 ;
  uint16_t dist ;
  uint16_t strength ;

  // Set at neutral, around 95 with this servo,
  // but jump to 80 and move slowly to center
  Serial.println("Centering") ;
  for (pos = 80; pos < 95; pos += 3)
  {
    myservo.write(pos) ;
    delay(200);
  }
  delay(1000) ;

  // transition from 'neutral' to -50
  Serial.println("Positioning") ;
  for (pos = 95; pos > 45; pos -= 3)
  {
    myservo.write(pos) ;
    delay(200) ;
  }
   
  // transition from -50 to +50
  Serial.println("Sweeping") ;

  // ten sweeps, then recenter
  for (int j = 0; j < 10; j++)
  {
    for (pos = 45; pos < 130; pos += 3)
    {                                 
      Serial.print(pos) ;
      Serial.print("\t") ;
      dist = tfmini.getDistance();
      strength = tfmini.getRecentSignalStrength();
 
      // Display the measurement
      Serial.print(dist);
      Serial.print(" cm\tsigstr: ");
      Serial.print(strength);

      // Make a pseudo bar chart of distances
      if (dist < 1200)
      {
        Serial.print("\t") ;
        for (int i = 0; i < dist; i += 10)
        {
          Serial.print("|") ;
        }
      }
      Serial.println() ;

      // move servo to next postion
      myservo.write(pos) ;
      delay(200);         // waits for the servo to reach the position
    }
    Serial.println() ;
 
    // transition from +50 to -50
    //Serial.println("Sweeping other direction") ;
    for (pos = 130; pos > 45; pos -= 3)     // goes from +50 to -50
    {                               
      Serial.print(pos) ;
      Serial.print("\t") ;
      dist = tfmini.getDistance();
      strength = tfmini.getRecentSignalStrength();
 
      // Display the measurement
      Serial.print(dist);
      Serial.print(" cm\tsigstr: ");
      Serial.print(strength);
 
      if (dist < 1200)
      {
        Serial.print("\t") ;
        for (int i = 0; i < dist; i += 10)
        {
          Serial.print("|") ;
        }
      }
      Serial.println() ;
     
      // Move to next position
      myservo.write(pos) ;
      delay(200);         // wait for the servo to reach the position
    }
    Serial.println() ;
  }
 
  // transition back from -50 to neutral
  Serial.println("Centering") ;
  for (pos = 45; pos < 95; pos += 3)
  {                                 
    myservo.write(pos) ;
    delay(200);                       // waits 15ms for the servo to reach the position
  }   
}


[Wiring picture attached]

So, center the servo, reposition to -50, sweep back and forth from -50 to +50 ten times, repeat.  Along the way, take readings with the TFMini.

Based on other recommendations, I have the servo on its own +5.3V 8A (measured) max power supply with grounds connected (actually, the motion is smoother with just my Ruggeduino, but the power drops too much, of course.)  I have a 470µf capacitor right before the leads for the motor.  I've tried various other suggestions to 'detach' after and 'reattach' before moving the servo; alter the servo pin to input after and back to output before moving; various changes to the step distance and timing; and making sure I'm not taking readings from the TFMini (software serial) or to the serial monitor during the moves (Serial).  As far as I can tell, Futaba servos are considered pretty good - I don't think that's the issue.  The servo runs the sweep example code smoothly, but a bigger range than I want and much faster than I want. 

My suspicion is that the various serial calls are all asynchronous, and what's happening is that they're stealing the interrupt and screwing up the signal to the servo.  That, I think, is what someone else meant when they said calls to Serial might be a problem.  (Like, here.)

What I can't seem to find is some explanation of exactly what's going on for one of these calls to position the servo, and what could go wrong with that. 

I think the next thing to try is disabling interrupts while moving the motor.  At least, I think that's what adding "TIMSK0=0;" in setup would be doing.  Any thoughts?

slipstick

I would think that a sweep would be smoother if you made more moves with a smaller delay between them e.g. increment/decrement by 1 and reduce delay to 70. No idea if that will help with the twitching though.

Steve

vinceherman

#2
May 16, 2018, 11:27 pm Last Edit: May 16, 2018, 11:28 pm by vinceherman
I bet your 2 libraries, Servo.h and SoftwareSerial.h, are in conflict over the timer.
You might try Servo2.h instead.

kjmclark

Steve, I spent yesterday changing that code from a step of one with delay of 20ms, to step of two with 40ms, to step of 5 with 100ms, to step of 10 with 200ms, and then back to step of three at delay of 60.  I bumped up the delay to 200 at the end, to see if spacing that code farther from the Serial and software serial would help.  The jitter problems happened at all of those steps and delays.  Usually it would run fine for the first sweep or two (or three, or four), then would get partway through a sweep and stutter - stop in the middle of moving, jump about 15 degrees, seem to recover, with about half the time smoothing back out, and half the time doing a whole series of stutter stops like that, until finally smoothing back out again for a while.  Seems fairly random as far as I can tell so far.

Vince - there's a servo2?  I'll go digging for that and try it out.  Is there some kind of tell-tale sign I could look for in debugging these things to decide if it's an interrupt issue?  There were occasional checksum errors on the TFMini responses, though I didn't think they correlated with the stutters - maybe I wasn't watching closely enough. I thought about commenting out all of the Serial calls, but if it's software serial causing the problem I can't do that as easily - though I could as a test.  But using another servo library might be performing the same test, the other way around.  I'll give it a shot, thanks! 

Ken

slipstick

I'm not sure about Servo2.h...to me it looks pretty much identical to the original Servo.h.

But you could definitely try ServoTimer2.h which avoids using Timer1 where most of those clashes arise.

Steve

vinceherman


kjmclark

Update.  I tried ServoTimer2.h, and it was a disaster.  Tremendous conflicts between the the servo and software serial.  The sensor was reporting communication errors left and right, and the servo either didn't move at all or jumped with huge jerky movements.  I haven't given up on that, but moved back to the regular servo call for more testing. 

Another thing I tried was using a variable power supply for the servo.  I was driving it with my Ruggeduino, with a voltage drop that didn't hurt anything, but not pleasant.  Then I switched to a good 5V switched supply with connected grounds.  That actually made things worse for the servo, but was needed for the Arduino anyway. 

So, with the variable supply, the servo was much smoother at 4.5V.  Still had problems, but not so bad.  When connected to the Arduino 5V supply, voltage dropped to 4.8V, which made me wonder about voltage going into the motor.  4.8V not so bad, 5.3V (from power supply) worse, so what voltage is this thing happy at?  Below 4.0, it didn't do anything at all.  Above 4.5, the jerkiness in the servo increased.

I bought two of these servo motors.  When I get the chance, I'm going to try the other one, to see if there's some difference.  I suppose while I'm at it, I should try the servo driven by one Arduino, and the sensor connected to another, to better isolate the problems.

Ken

jremington

#7
Today at 05:28 pm Last Edit: Today at 05:29 pm by jremington
Quote
When connected to the Arduino 5V supply, voltage dropped to 4.8V, which made me wonder about voltage going into the motor.
That is your problem.

NEVER power servos or motors from the Arduino power supply OR the 5V output. They inject noise, overload the voltage regulator and can actually destroy the Arduino.

Always use a separate power supply and connect the grounds. 4xAA batteries will work fine for one servo.

Go Up