Actually the pigpio Python module can do this quite easily for a single stepper. You would use the wave functions in combination with wave chains. Say you want a ramp of 20ms, 10ms, 5ms, 2ms, 1ms. You could create separate waves with 10ms on 10 ms off, 5 ms on 5 ms off, ..., 500 µs on, 500 µs off. You could then use a wave chain to send the first wave 100 times, the second 90 times, the third x times, etc. Here is some code which may help show the sort of thing I mean. It is for a stepper driver which requires pulsing the separate stepper coils. If you are using a pulse/direction stepper driver it would be quite a bit simpler. <!-- language: lang-py --> #!/usr/bin/env python import pigpio # http://abyz.me.uk/rpi/pigpio/python.html class stepper: """ A stepper class to return step pulses. """ def __init__(self, pi, g1, g2, g3, g4, delay=1000): """ """ self._pi = pi self._g1 = g1 self._g2 = g2 self._g3 = g3 self._g4 = g4 self._delay = delay self._all = (1<<g1 | 1<<g2 | 1<<g3 | 1<<g4) self._g1_mode = pi.get_mode(g1) self._g2_mode = pi.get_mode(g2) self._g3_mode = pi.get_mode(g3) self._g4_mode = pi.get_mode(g4) pi.set_mode(g1, pigpio.OUTPUT) pi.set_mode(g2, pigpio.OUTPUT) pi.set_mode(g3, pigpio.OUTPUT) pi.set_mode(g4, pigpio.OUTPUT) self._forward_wid = None self._backward_wid = None self._forward_wave_init(delay) self._backward_wave_init(delay) def _step_on(self, pos): if pos == 0: return (1<<self._g4) elif pos == 1: return (1<<self._g3 | 1<<self._g4) elif pos == 2: return (1<<self._g3) elif pos == 3: return (1<<self._g2 | 1<<self._g3) elif pos == 4: return (1<<self._g2) elif pos == 5: return (1<<self._g1 | 1<<self._g2) elif pos == 6: return (1<<self._g1) elif pos == 7: return (1<<self._g4 | 1<<self._g1) else: return 0 def _step_off(self, pos): return self._step_on(pos) ^ self._all def _forward_wave_init(self, delay): if self._forward_wid is not None: self._pi.wave_delete(self._forward_wid) self._forward_wid = None p=[] # pulses to drive stepper 1 cycle forward for i in range(8): p.append(pigpio.pulse(self._step_on(i), self._step_off(i), delay)) self._pi.wave_add_generic(p) self._forward_wid = self._pi.wave_create() def _backward_wave_init(self, delay): if self._backward_wid is not None: self._pi.wave_delete(self._backward_wid) self._backward_wid = None p=[] # pulses to drive stepper 1 cycle backward for i in range(8): p.append(pigpio.pulse(self._step_on(7-i), self._step_off(7-i), delay)) self._pi.wave_add_generic(p) self._backward_wid = self._pi.wave_create() def forward_wid(self): return self._forward_wid def backward_wid(self): return self._backward_wid def set_delay(self, delay): self._forward_wave_init(delay) self._backward_wave_init(delay) def cancel(self): self._pi.wave_delete(self._forward_wid) self._pi.wave_delete(self._backward_wid) self._pi.set_mode(self._g1, self._g1_mode) self._pi.set_mode(self._g2, self._g2_mode) self._pi.set_mode(self._g3, self._g3_mode) self._pi.set_mode(self._g4, self._g4_mode) if __name__ == "__main__": import time pi = pigpio.pi() pi.wave_clear() delay = 2000 s1 = stepper(pi, 2, 3, 4, 17, delay) s2 = stepper(pi, 14, 15, 18, 23, delay) for i in range(5): pi.wave_chain([ 255, 0, s1._forward_wid, s2._backward_wid, 255, 1, 0, 2, 255, 0, s2._forward_wid, s1._backward_wid, 255, 1, 0, 2, ]) while pi.wave_tx_busy(): time.sleep(0.1) delay -= 200 s1.set_delay(delay) s2.set_delay(delay) s1.cancel() s2.cancel() pi.stop()