joan2937 / pigpio

pigpio is a C library for the Raspberry which allows control of the General Purpose Input Outputs (GPIO).
The Unlicense
1.47k stars 410 forks source link

PWM self._servo.detach() can shorten last pulse width #543

Closed josephnarai closed 1 year ago

josephnarai commented 2 years ago

We want to use the pigpio for smooth motor operation and it works very well, except there is a bug which can make the last pwm pulse short, causing the motor to suddenly drive to a near 0 degreee position!

We have observed the pulses on an oscillicope and the motor drives as expected to it's target, and when the issue occurs, the last pulse width is very narrow.

We think that the issue is that the detatch, which ends up calling myGpioSetPwm with myGpioSetPwm 0 from 271 to 0, if called when the pulse is high, immediately zeros the output on the pin.

     else /* PWM STOP */
      {
         /* deschedule gpio on */

         for (i = 0; i < SUPERCYCLE; i += cycles)
            myClearGpioOn(gpio, i);

         for (i = 0; i < SUPERLEVEL; i += realRange)
            myClearGpioOff(gpio, i + oldOff);

         switchGpioOff = 1;
      }

While I don't fully undertsand the code, this appears to immediately clear the gpio. So there is no check to see if the pin is high before doing this ... or there is a defer mechanism, which perhaps should be used?

Any assistance for a workaround would be greatly apprecaited.

guymcswain commented 2 years ago

In the referenced code, there is a comment that clearly shows intent to wait until the last pulse has completed.

/ if in pulse then delay for the last cycle to complete /

I'm not sure if this should have been a 'defer' instead of clearing.

Let's see if Joan can enlighten.

guymcswain commented 2 years ago

Btw, please specify the API you are calling. From the title it is unclear if you are calling gpioServo or pwm variant.

josephnarai commented 2 years ago

Thanks for your reply.

I am accessing the library via the python function Servo, initialised like so:

     self._factory = PiGPIOFactory(host='localhost')
     self._servo = Servo(self._pinNumber, min_pulse_width=self._minPW, max_pulse_width=self._maxPW, pin_factory=self._factory)

And then we control the servo via

self._servo.value = newValue and

self._servo.detach()

when detatching...

However, when I debug the calls into the pigpio library, myGpioSetPwm(unsigned gpio, int oldVal, int newVal) is being called NOT myGpioSetServo(unsigned gpio, int oldVal, int newVal)!

So that perhaps explains why we are seeing this issue, as the wrong Set function is being called!?

Are we doing something wrong in the way we are calling the servo function from python?

josephnarai commented 2 years ago

Ah, we were referencing several examples which had the above method for the servo... reading the (https://abyz.me.uk/rpi/pigpio/python.html#pulsewidth) documentation, we should be using:

set_servo_pulsewidth([user_gpio](https://abyz.me.uk/rpi/pigpio/python.html#user_gpio), [pulsewidth])

I'll try that now, hopefully that will resolve the issue.

I fear lots of people are using the wrong method to control the servo!