Servo library serious bug

Hi,

I am controlling a brushless motor using ESC with servo.h library. It's really good and easy to use but there is a bug that could cause serious injuries!

After using my quad I send a command from my trnsmitter to tell the motors to stop spining. In the receiver (quadcopter) I simply send writeMicroseconds(1000) (this is the stop pulse) for 3 seconds to make sure each ESC receives this 1000us pulse, and finally I use detach().

Well, most of the time it works fine, I mean, all the motors stop spining correctly. BUT there is a bug that only today I discovered the guilty: sometimes when I send the stop command from the transmitter the motors stop and keep stopped for about 3 seconds (it was expected) BUT right after the 3 seconds one or more of the motors starts spinning REALLY fast for a while and stop.

After messing a lot I discovered that the detach method is the guilty! Think with me: when I set the command writeMicroseconds(1000) to my motors, arduino keeps sending this 1000us pulse to every motor BUT sometimes when I use detach and arduino is sending the 1000us it simply stops sending that 1000us pulse and my ESC receives a pulse smaller than 1000us cause when I called detach Servo library simply stopped the pulse instead of finishing it and avoiding sending a different length pulse.

I took about 3 months to finally decide to discover what was causing this problem and after get a minimal code I realized that the detach() is indeed causing, sometimes, the motors to spin when they should not!

So don't detach() until you have switched off the power to the motors.

I think that would be normal practice with any RC system - AFAIK you never switch off the receiver before you switch off the motor power.

...R

@gilperon: Please can you stop this knee-jerk "everything is broken and I'm the only person who knows" crap, and start THINKING.
It's getting really tedious.

I don't have an oscilloscope but it should be easy to confirm that detach does not stop the signal to the servo but are you sure that the problem is not with the ESCs ?

In any case, the obvious thing to do is not to detach the servos to ensure that the ESCs stay turned off whilst receiving a continuous 1000us signal.

I took about 3 months to finally decide to discover what was causing this problem and after get a minimal code I realized that the detach() is indeed causing, sometimes, the motors to spin when they should not!

This sounds like something posted by somebody fairly recently, perhaps you? As best as I remember there are certain safety protocols that are recommended with use of ESCs and motors. I think the big picture is always have a stable control signal before the ESC is energized/deenergized. A malformed control pulse can cause the ESC to do most anything while the ESC is armed.

Edit: thought that sounded familiar...

http://forum.arduino.cc/index.php?topic=304663.0

I am not saying I am smart, but detach should wait for the pulse being sent before completely stop sending the pulses.

Anyway, you dont look like wanna help, so I will move on and live with this potentilly deadly bug that nobody here cares.

Have you submitted a bug report?

gilperon:
I am not saying I am smart, but detach should wait for the pulse being sent before completely stop sending the pulses.

It does.

gilperon:
Anyway, you dont look like wanna help, so I will move on and live with this potentilly deadly bug that nobody here cares.

No, you will go on refusing to admit that the problem is either in your wiring or your code and keep blaming all your failings on libraries that seem to work fine for everyone else. And as a consequence you will be living with a deadly bug in your copter that could hurt you.

aarg:
Have you submitted a bug report?

That is premature. @gilperon needs to provide a test case including a sketch and information about the hardware.

That doesn't sound difficult.

Also, the code is in the public domain, no? So it would be helpful to identify the specific problem in the code, and develop a fix. Rather than expect someone else to pursue it.

And probably some scope output to show that the pulse is indeed short. That shouldn't be hard to do.

AWOL:
@gilperon: Please can you stop this knee-jerk "everything is broken and I'm the only person who knows" crap, and start THINKING.
It's getting really tedious.

Direct from github - here is YOUR crap!

void Servo::detach()
{
servos[this->servoIndex].Pin.isActive = false;

#ifdef FREE_TIMERS
if(isTimerActive(SERVO_INDEX_TO_TIMER(servoIndex)) == false) {
;// call to unimplimented function in wiring.c to re-init timer (set timer back to PWM mode) TODO?
}
#endif
}

It's easy to reprocude the bug you just need a motor and a bit of luck or an osciloscope, which I dont have. Run your servo for a few seconds and after that try to detach it and hope that you are detaching while the pulse is being sent; if so a wrong pulse width will be sent.

gilperon:
It's easy to reprocude the bug you just need a motor and a bit of luck or an osciloscope, which I dont have. Run your servo for a few seconds and after that try to detach it and hope that you are detaching while the pulse is being sent; if so a wrong pulse width will be sent.

If it's that important, especially where safety is involved, why on earth would you even call detach() without first making damned SURE the previous operation was completed? That's just poor design on your part that I would not tolerate from any programmer working for me....

Regards,
Ray L.

Vaclav:
Direct from github - here is YOUR crap!

Who's that for?

What code is that?

RayLivingston:
why on earth would you even call detach() without first making damned SURE the previous operation was completed?

I think the point the OP is making is that the resend of the pulse (which happens every 20ms as a consequence of either a servo.attach or servo.write) might not be complete when he does the servo.detach.

He has no control over that: the pulse is sent every 20ms to hold the servo, and it seems there's a chance that the detach might happen in the middle of such an automatically generated pulse. The scope trace attached shows the repeated 1.5ms pulse for an attached, centralised servo.

servo attached.jpg

gilperon:
... need a motor ... Run your servo ...

Which?

@RayLivingston if a buggy library does not handle the detach right, WHY DOES IT OFFER detach??? You say you dont tolerate that kind of thing, but you probably use this buggy servo library. It's a poor design offer a method that does not work as it should, using your words.

There are MANY reasons I want to detach before turn everything off. Be creative and you can find those reasons. I will give you one very simple: after I finish my flight with my quad I need to proccess lots of data and save it in the eeprom which consumes a LOT of arduino processing power. The problem? While I am processing this data servo library does not work well sending the 1000 us pulses and I frequently experience motors spinning while processing this data cause arduino cant handle the data being processed while keeping the 1000 us pulses being sent to my ESC.

IF I detach() all ESCs before processing the data I will rest assured that my motors WILL NOT SPIN even if arduino behaves strangely.

It's sad I need to explaing such a thing, independently of why I need to detach, there is a bug and people should be talking about how to fix it, not why am I doing a "stupid" thing detaching the ESCs.

@JimboZA you got it right, but I mean this: if I want for example to send a 1000us pulse you know that arduino will send 1000us high + 19000us low. Right? There is no problem when I detach and arduino is processing the 19000us low, it does not make my servo spin. The problem is when the detach is executed WHILE sending the 1000us high pulse, cause if it detaches in the middle of this 1000us pulse, generating 500us pulse, my ESC will make the motor spin cause it received a 500us pulse.

Sending the 19000us pulse longer or a little shorter does not make any problem, at least to my case.

If detach() just clears an enable variable, isn't it unlikely that it would terminate a pulse? Just saying. Why would a timer routine keep checking it? You would expect it to check at most at the beginning and end of a pulse. Something to look into.