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.
#!/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()