servo sweep using writeMicroseconds

Hi Group,

As I would like to test my servo's movement on forehand.
As I am using the writeMicroseconds from the servo library, I was looking for a sweep sketch using that. But no sucess finding anything I decided to adapt the origional sketch found in the example section. Keeping in mind that 0 degree is 100 mS and 180 degree is 200 mS. code below

#include <Servo.h>
Servo myservo;  // create servo object to control a servo

int pos = 0;    // variable to store the servo position

void setup() {
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}
void loop() {
  for (pos = 1000; pos <= 2000; pos += 10) { // goes from 0 degrees to 180 degrees
    myservo.writeMicroseconds(pos);
    delay(25);                               // waits 25ms for the servo to reach the position
  }
  delay(1000);
  for (pos = 2000; pos >= 1000; pos -= 10) { // goes from 180 degrees to 0 degrees
    myservo.writeMicroseconds(pos);
    delay(25);                               // waits 25ms for the servo to reach the position
  }
  delay(1000);
}

In basic this sketch should do the same as the origional sketch but it doesnt.
testing my servo's with the basic sweep the move perfect from 0-90-180 degree
But my changed sketch moves from som angle to 90 and some other angel.
So what could be wrong with my sketch??

Used servo's are DS3218mg, SG900s ,g90, and RDS3120mg, all showing the same behaivior.

Regards, Harry

You did mean to say 0 is 1000 uS and 180 is 2000 uS? That’s what you’ve written in code, where it matters…

The servo example works for you? Then your change to it should work, yes.

the servo attach can take two more parameters, min_pikse_width and max_pukse_width, try calling it with plausible values or experiment with the values, viz:

myservo.attach(9, 1000, 2000);

HTH

a7

Interesting.

I been using 0=500us and 180 = 2500us for a total of 2000 of travel. Which produces ~11.11us per degree.

refer to writeMicroseconds()

Writes a value in microseconds (uS) to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft. On standard servos a parameter value of 1000 is fully counter-clockwise, 2000 is fully clockwise, and 1500 is in the middle.

Note that some manufactures do not follow this standard very closely so that servos often respond to values between 700 and 2300. Feel free to increase these endpoints until the servo no longer continues to increase its range. Note however that attempting to drive a servo past its endpoints (often indicated by a growling sound) is a high-current state, and should be avoided.

#include <ESP32Servo.h>
// create four servo objects
Servo servo1;
Servo servo2;
Servo servo3;
// Servo servo4;

// Published values for SG90 servos; adjust if needed
#define MINservo 1400
#define MAXservo 1600
#define ServoIncrement 11
#define SerialDataBits 115200
#define iX_90z 1475 // 1400 is to the right
#define iX_90y 1435 // 1400 tilts forward
#define iX_90x 1500

// These are all GPIO pins on the ESP32
// Recommended pins include 2,4,12-19,21-23,25-27,32-33
int servo1Pin = 4;
int servo2Pin = 32;
int servo3Pin = 33;
// int servo4Pin = 23;

int pos = 500;      // position in microseconds

void setup()
{
  Serial.begin( SerialDataBits );

  servo1.setPeriodHertz(50);      // Standard 50hz servo
  servo2.setPeriodHertz(50);      // Standard 50hz servo
  servo3.setPeriodHertz(50);      // Standard 50hz servo
  //	servo4.setPeriodHertz(50);      // Standard 50hz servo

  servo1.attach(servo1Pin);
  servo2.attach(servo2Pin, MINservo, MAXservo);
  servo3.attach(servo3Pin, MINservo, MAXservo);
  // servo4.attach(servo4Pin, MINservo, MAXservo);
  servo1.writeMicroseconds( iX_90z );
  delay(20);
  servo2.writeMicroseconds( iX_90y );
  delay(20);
  servo3.writeMicroseconds( iX_90x );
  delay(20);


}

void loop()
{


  for (pos = MINservo; pos <= MAXservo; pos += ServoIncrement) { // sweep from A degrees to Z degrees
    Serial.print ( "+" );
    Serial.println ( pos );
    servo1.writeMicroseconds ( pos ); // z servo
    delay(10);             // waits Xms for the servo to reach the position
    servo2.writeMicroseconds ( pos );
    delay(10);             // waits Xms for the servo to reach the position
    servo3.writeMicroseconds ( pos );
    delay(10);             // waits 20ms for the servo to reach the position
  }
  for (pos = MAXservo; pos >= MINservo; pos -= ServoIncrement) { // sweep from A degrees to Z degrees
    Serial.print ( "-" );
    Serial.println ( pos );
    servo1.writeMicroseconds ( pos );
    delay(10);             // waits Xms for the servo to reach the position
    servo2.writeMicroseconds ( pos );
    delay(10);
    servo3.writeMicroseconds ( pos );
    delay(10);             // waits Xms for the servo to reach the position
  }
  
}

A servo sweep using us written for an ESP32 adapted from Uno code. I'm sure it can be adapted back to Uno code.

How about a POT and a servo with the serial monitor showing the resulting pulse width?

I'm not positive this'll work. I don't have a POT here to test it with. But I put in some values and the servo runs. It would be good to see what the servo likes as end points..

#include <blinker.h>
#include <mapper.h>

#define  SERVO_PIN   4
#define SERVO_MAX_MS   2.0
#define SERVO_MIN_MS   1.0

blinker  servoSignal(SERVO_PIN,1.5,19.0);                         // Set up servo at 1.5 ms every 19 ms. Little less than 20 ms.
mapper   pwMapper(0,1023,SERVO_MIN_MS/2.0,SERVO_MAX_MS*2.0);      // We'll map 1/2 * Servo min to 2 * Servo max. Just to see how it works.
int      gPOTVal;                                                 // A global to save our last POT reading.

void setup() {

   Serial.begin(9600);          // Fire up serial.
   gPOTVal = -1;                 // Impossible value as flag.
   setServo();                   // Set up siganl to match the POT.
   servoSignal.setOnOff(true);   // Fire up servo signal.
}


void setServo(void) {
   
   float pulseWidth;
   int   localPOTVal;
   
   localPOTVal = analogRead(A0);          // Read the POT.
   if ( localPOTVal != gPOTVal) {         // If the POT value has changed since last time..
      gPOTVal = localPOTVal;              // Update the global POT value.
      pulseWidth = pwMapper.map(gPOTVal); // Map the POT value to the desired pulse width.
      servoSignal.setPulse(pulseWidth);   // Update the pulse width.
      Serial.print("PW : ");              // Lets show the user what we did.
      Serial.println(pulseWidth);         //
   }
}


void loop(void) {
    
   idle();        // Run background stuff, like the squarewave.
   setServo();    // Do the read POT set servo thing.
}

If you're interested in trying this. You'll need LC_baseTools from the library manager installed to compile it.

Have fun!

-jim lee

@IDwalker you have 11 uS steps and it take ~180 of them for your loops, but

where did 1400 and 1600 come from? ‘A’ data sheet I found for the SG90 just shows the more or less standard 50 Hz signal with pulse width ranging from 1000 uS to 2000 uS.

In any case, some experiments should help. An oscilloscope might help more, but.

@jimLee no pot, huh? I got pot, no servo...

a7

alto777:
@jimLee no pot, huh? I got pot, no servo...

a7

Haha no. I'm sitting at the kitchen table. I did have a servo in my briefcase (lunchbox). But no POT. I do have a button though. Couple handhelds, mp3 player and the home made cellphone. A few Teensy 3.2s..

No POT.

-jim lee

The default values for the Servo library when not specified in the attach() are 544us = 0 and 2400us = 180 (defined in Servo.h). Try those in place of 1000 - 2000 and it should move to the same positions as the original Sweep.

Steve

alto777:
@IDwalker you have 11 uS steps and it take ~180 of them for your loops, but

where did 1400 and 1600 come from?

The numbers are limits I imposed on the sweep based upon the servos physical mounting.

Normally, 0 degrees = 544 micros, 90 = 1472, 180 = 2400, but play with this tester:

/*
 Try this test sketch with the Servo library to see how your
 servo responds to different settings, type a position
 (0 to 180) or if you type a number greater than 180 it will be
 interpreted as microseconds(544 to 2400), in the top of serial
 monitor and hit [ENTER], start at 90 (or 1472) and work your
 way toward zero (544) 5 degrees (or 50 micros) at a time, then
 toward 180 (2400). 
*/
#include <Servo.h>
Servo servo;

void setup() {
  // initialize serial:
  Serial.begin(9600); //set serial monitor baud rate to match
  servo.write(90);
  servo.attach(9);
  prntIt();
}

void loop() {
  // if there's any serial available, read it:
  while (Serial.available() > 0) {

    // look for the next valid integer in the incoming serial stream:
    int pos = Serial.parseInt();
    pos = constrain(pos, 0, 2400);
    servo.write(pos);
    prntIt();
  }
}
void prntIt()
{
  Serial.print("  degrees = "); 
  Serial.print(servo.read());
  Serial.print("\t");
  Serial.print("microseconds =  ");
  Serial.println(servo.readMicroseconds());
}

JCA34F:
OK I uploaded the sketch and i have the same results 544mS=0degree and 2400 mS=180degree.

Maybe I have missed somthing but in my other sketch I am working on, where a X/Y position is received in degree such as 135.8 or 22.4 . at the moment I am using this code to convert to mS

unsigned int degree2ms(float degrees) {

return 1000 + degrees * 150 / 27;
}

an * subsitute the 111111000+degrees ... with 544+degrees..... ??*

180 degrees = 2400 - 544 = 1856 micros, 1 degree = 1856 / 180 = 10.3111111111 degrees
micros = degrees * 10.311 + 544.05

If you want the range 544 to 2400 to represent 0 to 180 degrees, multiply degrees by ((2400-544) /180.0) and add 544.

return 544 + degrees * ((2400-544) /180.0);

Don't worry about pre-calculating anything, like putting in 1856 in place of (2400-544) because the compiler will do all the constant math at compile time and multiply 'degrees' by the constant '10.31111'.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.