Oneshot timer?

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
rankor
Posts: 38
Joined: Sun Nov 30, 2014 12:38 am

Oneshot timer?

Post by rankor » Mon Jan 05, 2015 5:02 am

It seems it is not possible to call timer.deinit() and timer.callback(None) from the callback itself?

How can I make sure that once the callback has been called once, it will not get called again? Preferrably the timer should be completely disabled after the callback has been called.

It would be helpful if there was a oneshot timer for the purpose below. It is a class that makes it possible to use the continous rotation servo to rotate to an angle. Works but needs calibration.


Code: Select all

import pyb
import math

class ServoConverter( object ):
    def __init__( self, servo, timer ):
        self._servo = pyb.Servo( servo )
        self._speed = 100
        self._timer = pyb.Timer( timer )

    def _initTimer( self, frequency ):
        self._timer.init( freq=frequency )

    def _timePassed( self, t ):
        self._servo.speed( 0 )

    def rotate( self, degrees ):
        time = abs( degrees * 1.94 )
        freq = int( 1000 / time )

        self._timer.callback( None )
        self._timer.deinit()
        self._initTimer( freq )

        self._timer.callback( self._timePassed )

        if degrees >= 0:
            self._servo.speed( self._speed )
        else:
            self._servo.speed( -self._speed )

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Oneshot timer?

Post by dhylands » Mon Jan 05, 2015 6:44 am

rankor wrote:It seems it is not possible to call timer.deinit() and timer.callback(None) from the callback itself?
I don't see any reason why setting the callback to None shouldn't work from within the callback.

I modified this program: https://github.com/dhylands/upy-example ... eat_irq.py
and made it look like this:

Code: Select all

import pyb
import micropython

class Heartbeat(object):

    def __init__(self):
        self.tick = 0
        self.led = pyb.LED(4) # 4 = Blue
        self.tim = pyb.Timer(4)
        self.tim.init(freq=10)
        self.tim.callback(self.heartbeat_cb)

    def heartbeat_cb(self, tim):
        if self.tick <= 3:
            self.led.toggle()
        self.tick = (self.tick + 1) % 10
        if self.tick == 9:
            self.tim.callback(None)

micropython.alloc_emergency_exception_buf(100)
Heartbeat()
and it seems to work fine.
rankor wrote:How can I make sure that once the callback has been called once, it will not get called again? Preferrably the timer should be completely disabled after the callback has been called.
Setting the callback to None, disables the interrupt. The timer still runs in the background, but doesn't consume any CPU cycles.
rankor wrote:It would be helpful if there was a oneshot timer for the purpose below. It is a class that makes it possible to use the continous rotation servo to rotate to an angle. Works but needs calibration.
I also replaced the call to self.timer.callback(None) with self.timer.deinit() and that also seemed to work fine.

Did you have an example that isn't working for you?

Knowing how continuous servos work, I'm not sure how a one-shot could be used to turn a continuous rotation servo to a particular angle. At least not in any reliable fashion, unless you add an encoder or some other type of feedback.

rankor
Posts: 38
Joined: Sun Nov 30, 2014 12:38 am

Re: Oneshot timer?

Post by rankor » Mon Jan 05, 2015 10:59 pm

It didn't work for me to disable the callback in the callback, I'll post some code later.

About tranforming a continous servo to one for angles, maybe it won't be perfect but setting the speed and rotating for a certain time will move the arm X degreees. That is not the same but if you save the current position you could. But maybe that will accumulate a big error eventually.

Oh well, I will buy some angle servos instead.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Oneshot timer?

Post by dhylands » Tue Jan 06, 2015 3:28 am

The problem I see is that you need to compensate for accel and decel of the servo.

The speed will also vary with voltage.

If we assume 120 RPM, that's 2 rotations per second. If we sent out the pulse to set the speed at say 60 times per second, the servo would rotate 1/30 of a rotation or about 12 degrees (at the fastest speed).

That's without considering accel and decel. I think you'll find that the errors will accumulate pretty quickly. I did some tests a few years ago and also prepared some plots:
http://davehylands.com/Robotics/Servos/
You can see the accel and decel in the Sweep plot.

Post Reply