Search code examples
pythonpygamejoystick

Ramping Joystick values over time


I have a python script that reads the input signal of a joystick via pygame and passes that input to a motor controller.

Now i would like to add a ramping function. let's say to ramp up to the input value with a given delay. if the input of the joystick is '100' it should only pass that value to the motor controller after the delay has passed and 'fade' in between.

Also, it would be a plus to define the ramp. (linear or logarithmic curve)

Is there a simple way of doing that? thanks for your help!


Solution

  • A simple class could look like this:

    class RampUp:
        def __init__(self):
            self.value = 0
            self.target = 0
            self.next = self.__next__
            self.calc = None
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.value == self.target:
                return self.value
            else:
                self.value = self.calc(self.value, self.target)
                return self.value 
    

    this class simply holds a state, is iterable and calls a function that calculates a new value in every iteration.

    A simple "ramp" function that simply increases the output value by a given delta could be:

    def simple(value, target):
        if value < target:
            value = min(value + 1, target)
        else:
            value = max(value - 1, target)
        return value
    

    Example of usage:

    gen = RampUp()
    gen.calc = simple
    gen.target = 20
    for _ in xrange(100):
        # that's the value you pass to your motor controller
        print next(gen)
    

    Another example ramp function that is more complex:

    def smooth(value, target):
        # maximum acceleration is 2
        delta_max = 2
        # minimun acceleration is 0.5
        delta = max(0.5, (abs(target) - abs(target-value)) / 10.)
        delta = min(delta, delta_max)
        if value < target:
            value = min(value + delta, target)
        else:
            value = max(value - delta, target)
        return value
    

    In response to your comment:

    def with_step(step):            
        def simple(value, target):
            if value < target:
                value = min(value + step, target)
            else:
                value = max(value - step, target)
            return value            
        return simple
    
    gen = RampUp()
    gen.target = 20
    # you could move this line into the class
    # reaches the target value in 12 steps
    gen.calc = with_step((gen.target - gen.value)/12.)