Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Servo lib has 15ms delay since ESP8266 V3.0.0 #8081

Closed
makerobotics opened this issue May 27, 2021 · 22 comments · May be fixed by #8011
Closed

Servo lib has 15ms delay since ESP8266 V3.0.0 #8081

makerobotics opened this issue May 27, 2021 · 22 comments · May be fixed by #8011

Comments

@makerobotics
Copy link

Basic Infos

  • [x ] This issue complies with the issue POLICY doc.
  • [x ] I have read the documentation at readthedocs and the issue is not addressed there.
  • [x ] I have tested that the issue is present in current master branch (aka latest git).
  • [x ] I have searched the issue tracker for a similar issue.
  • [x ] I have filled out all fields below.

Platform

  • Hardware: [ESP8266]
  • Core Version: [3.0.0]
  • Development Env: [Arduino IDE]
  • Operating System: [Ubuntu]

Settings in IDE

  • Module: [Wemos D1 mini r2]
  • Flash Size: [4MB]
  • lwip Variant: [v2 Lower Memory]
  • Reset Method: [nodemcu]
  • Flash Frequency: [40Mhz]
  • CPU Frequency: [80Mhz]
  • Upload Using: [SERIAL]
  • Upload Speed: [115200] (serial upload only)

Problem Description

I am programming a useless box with a Wemos D1 mini.
I use a servo : "myservo.write(pos); "
Since the board update to V3.0.0, there is a delay in the servo write instruction (15ms as I could trace).
If I go back to a later board version, this problem is no more present. The servo lib version is not changing anything.

MCVE Sketch

#include <Arduino.h>
#include <Servo.h>

Servo myservo;  // create servo object to control a servo
unsigned long timestamps[4];

void scenarioStepMoveToContact(int delayscenarioStep){
//  timestamps[0] = millis();
  pos--;
  //Serial.println(pos);
//  timestamps[1] = millis();
  myservo.write(pos);                 // tell servo to go to position in variable 'pos'
//  timestamps[2] = millis();
  delay(delayscenarioStep);
  if(!isPushed()){
    Serial.println("Reached contact");
    scenarioStep++;
    btnLock = 0; // unlock next cycle
    Serial.println("unlock");
  }
  /* Safety */
  else if(pos<ENDPOS){
    Serial.println("Reached end position");
    btnLock = 0; // unlock next cycle [DEBUG]
    Serial.println("Unlock");
    scenarioStep++;
  }
//  timestamps[3] = millis();
}

void setup() {
  myservo.attach(SERVO);        // attaches the servo on GIOxx to the servo object
  myservo.write(SERVO_STANDBY); // start servo at STANDBY deg

}

void loop() {
  // this is not the real code, but enough to understand the example...
  scenarioStepMoveToContact(5);
}

Time between the timestamps is 15ms as I use the V3.0.0 board.

@dok-net
Copy link
Contributor

dok-net commented May 28, 2021

there is a delay in the servo write instruction (15ms as I could trace).

Servo.h:

#define REFRESH_INTERVAL            20000 // classic default period to refresh servos in microseconds

This is according to servo specification, and has been in the code for at least 6 years. If you take some extra time to update your code snippet to an actual MCVE, one that must compile (verifiable), and isn't full of commented lines (minimum), your chances of getting support are much better.

When planning issue reports in the future, please consider:

If I go back to a later board version, this problem is no more present.

Your use of "Later" is probably lost in translation, you mean an earlier version, but please always be specific when reporting issues.

The servo lib version is not changing anything.

This applies to a few other libraries as well, so please check first, then try, then report:
There is no such thing as a "Servo lib version" for ESP8266, as the "library" is part of the ESP8266 Core. Probably it's even safer to uninstall any Servo lib from the Arduino library manager while building for the ESP8266.

@makerobotics
Copy link
Author

makerobotics commented May 28, 2021 via email

@dok-net
Copy link
Contributor

dok-net commented May 28, 2021

@makerobotics Please fix the code block, we can't copy & paste without editing all the line breaks by hand.

@d-a-v
Copy link
Collaborator

d-a-v commented May 28, 2021

I tried to fix as I usually do but in this case: "Email replies do not support Markdown"

(so I edit my post and do the copy-paste myself)

#include <Servo.h>

#define SERVO           16

Servo myservo;  // create servo object to control a servo
unsigned long timestamps[4];
int pos = 0;

void setup() {
  Serial.begin(115200);
  myservo.attach(SERVO);        // attaches the servo on GIOxx to the servo object
  myservo.write(0);
  delay(500);                   // wait for servo to be in position
}

void loop() {
  for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees in steps of 1 degree
    timestamps[0] = millis();
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    timestamps[1] = millis();
    delay(5);                       // waits 5ms for the servo to reach the position
    timestamps[2] = millis();
    Serial.print(timestamps[0]);Serial.print(" ");
    Serial.print(timestamps[1]-timestamps[0]);Serial.print(" ");
    Serial.print(timestamps[2]-timestamps[1]);Serial.println(" ");
  }
  for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(5);                       // waits 5ms for the servo to reach the position
  }
}

@dok-net
Copy link
Contributor

dok-net commented May 28, 2021

@makerobotics You must have hit "the wrong button" :-)
Anyway: For an immediate fix, you can switch over to another waveform generator (full disclosure: I am the author of that alternative implementation).
Like so (adding enablePhaseLockedWaveform()):

void setup() {
   enablePhaseLockedWaveform();
   Serial.begin(115200);
   myservo.attach(SERVO);        // attaches the servo on GIOxx to the servo object
       myservo.write(0);
   delay(500);                   // wait for servo to be in position
}

@dok-net
Copy link
Contributor

dok-net commented May 28, 2021

@earlephilhower I have only tested that the "phase locked" generator gives instant returns from servo.write, no more, no less, and I don't really know why "pwm locked" apparently delays for up to 20ms (15 = 20 - 5). Please take it from here?

@dok-net
Copy link
Contributor

dok-net commented May 28, 2021

A bit more analysis for the benefit of my pending PRs, to whom it may concern. This issue remains in PR #8008 ("pwm locked"). See how compatible it is ;-)

@dok-net
Copy link
Contributor

dok-net commented May 28, 2021

1100 0 5 
1105 1 5 
1111 0 5 
1116 0 5 
1121 0 5 
1126 0 5 
1131 0 5 
1136 0 5 
1141 0 5 
1146 0 5 
1151 0 5 
1156 0 5 
1161 0 5 
1166 0 5 
1171 0 5 
1176 1 5 

Caveat: I haven't attached a servo, don't know if this would go up in flames...

@Tech-TX
Copy link
Contributor

Tech-TX commented May 29, 2021

@dok-net The servo doesn't flambé, but it does move about 3-4 times faster with your branch, Dirk.

edit: This may also explain what I saw with my PWM test routines a month ago before I disappeared: the analogWrite() ramp-up ramp-down was running a lot slower than previously.

Minor comment: my servo only goes through about 90 degrees of arc (not 180), typical for an aircraft or hobby servo.

@Tech-TX
Copy link
Contributor

Tech-TX commented May 31, 2021

@makerobotics your code isn't doing what you've programmed it for, at least not exactly. You're trying to update the servo every 5mS, but the period of a 50Hz servo signal is 20mS. When it's working 'correctly', the ESP is actually updating the servo position by 4 degrees every 20mS, and not by 1 degree every 5mS. You can't update the servo signal DURING the cycle, only when it starts a new cycle or else it would jitter horribly.

@makerobotics
Copy link
Author

makerobotics commented May 31, 2021 via email

@Tech-TX
Copy link
Contributor

Tech-TX commented Jun 1, 2021

No worries, we're looking to see where the strange behavior comes in.

If you're using 'digital' servos (like the tail rotor on a helicopter) you could be running a 5mS refresh rate, but you'd have to change the refresh rate in servo.h,

#define REFRESH_INTERVAL    20000     // minimum time to refresh servos in microseconds 

For modern RC systems, that refresh rate can be anything from 50Hz (ancient analog spec) up to about 333Hz maximum. 5ms is a 200Hz refresh rate, which might work depending on your servos. Some servos will chatter or jitter above ~ 100Hz, some work OK up to 333Hz.

If you add the line in setup that dok-net mentioned above, the servo function doesn't block like the default version does,

enablePhaseLockedWaveform();

so you'll get the expected motion, depending on your refresh rate: at 200Hz it'll step in 1 degree increments, and at 50Hz it'll step in 4 degree increments. The underlying issue should be corrected in the git version of the repo sometime soon, but it could be months before it's rolled into the board manager version. In the meantime, the enablePhaseLockedWaveform(); should fix you up.

@makerobotics
Copy link
Author

Thank you all for the kind help.
I could not find the documentation about enablePhaseLockedWaveform(), but I will try it soon.
I also noticed a difference in the servo positions. I mounted a 180° servo, and the positions are not the same with the V3.0.0.
Is it locked to 0-90° ?
Unfortunately, my hardware is not available currently to compare on this level. I will investigate as soon as I have my HW back.

@dok-net
Copy link
Contributor

dok-net commented Jun 5, 2021

Find out the extreme min and max and set them in the respective call to to the servo channel. You'll know what I mean if you look at the header file.

@makerobotics
Copy link
Author

Sorry I was probably unclear again.
It seems that my servo is no more able to go to the old min and max positions with the V3.0.0 lib.
Of course I can set new extreme positions, but my servo is not more able to achieve all the angles.

@d-a-v
Copy link
Collaborator

d-a-v commented Jun 5, 2021

@makerobotics
Default min max have changed in v3.0.0:
Previous value were MIN:544 MAX:2400 (in 2.7.4 and previous version of this core)
Current values are MIN:1000 MAX:2000 (see #7023)
You can change the current defaults using uint8_t attach(int pin, uint16_t min, uint16_t max, int value);. This method will also work with previous versions of this arduino platform.

@makerobotics
Copy link
Author

Thanks again for your help.

@dok-net
Copy link
Contributor

dok-net commented Jul 15, 2021

@makerobotics I would like to think that in addition to @d-a-v's remark this https://github.com/connected-little-boxes/box-code/issues/8#issuecomment-880585908 provides closure to this issue. If so, would you like to promote it to solved/closed, unless there's something else unresolved?

@makerobotics
Copy link
Author

Thanks all for your fast support. I will close the issue as there is a possibility with the attach function to bypass the problems.
But I still think it is more difficult to use (even if more secure) than in the previous version.
Some comments in the Arduino example would be nice (and also the attach function call).

@sercona
Copy link

sercona commented Sep 8, 2021

fwiw, I just ran into this, as well. I was using 2.x ESP core and all was well with my servo project. I upgraded to 3.x and all the servo code went to 90degrees swing instead of 180. it wasted hours of my time, too. I have to disagree with this 'fix', for the record. you broke code that used to run. to push this on the apps and have APP CODE BE UPDATED was the wrong approach to this. better to create new api's or names and let people migrate GRACEFULLY over to the new version.

@sercona
Copy link

sercona commented Sep 8, 2021

But the behaviour was charged. In previous version, my code was working fine even by calling the function every 5 ms. I can change my code accordingly

this is my complaint; all of a sudden things break for an application and we (apps writers) have to scramble to find out what caused it. I have to strongly disagree with how this was handled, guys. this is what temps me to LOCK DOWN all the dependances in any of my projects since too many things change under you if you dont. you should not have to do that (keeping local copies of critical system libs) but it seems that if you want your project to build and always build, you cant count on system libs staying working. how absurd is that?

@d-a-v
Copy link
Collaborator

d-a-v commented Sep 9, 2021

These change were motivated by this comment.
We had to decide between destroying hardware and a documented software breaking change.
Locking down dependencies and reading breaking change list before updating them is a good practice.

I upgraded to 3.x and all the servo code went to 90degrees swing instead of 180

This however looks strange. You seem to be the first with such report. Are you using our embedded Servo library ?

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants