2

I'm trying to make a function which would output a pulse frequency , given a Ts (time.sleep(ts) on my function) The function is for later use on an acceleration ramp for a stepper motor , as the driver works on a pulse train ,right now I made a function which sets an output to low and high with a time.sleep between them , and it works , however viewed on an osciloscope , it is not as exact as I would like

this is my python code

def ts_2_freq( ts ):
    #GPIO.output(self.pin_direccion , direccion)
    print("Funcionando con Ts={}".format(ts))
    for i in xrange(0,1):

        GPIO.output(self.pin_pulse,False)
        time.sleep(ts)
        GPIO.output(self.pin_pulse,True)
        time.sleep(ts)

for i in xrange(1000,1,-1):
    ts_2_freq(0.005)

which outputs the following pulse train

enter image description here

As you can see the pulse isnt on time every 5ms as expected , so I was hoping a C library would make it , but I need to be able to call it via python , as my whole code is on python (this code later comunicates to a python gui on tkinter)

this code would be used in 2 ways , setting an acceleration ramp (calling it multiple times) , and to give the motor an aproximate velocity based on pulse frequency , this is later corrected by a PID controller any help on a library that generates me this , also other ideas to solve it are welcome . I made some tests modifying the pigpio PWM frequency , but it has specific steps , and I cannot set an intemediate frequency

>>> pi.set_PWM_frequency(26,1000)
1000L
>>> pi.set_PWM_frequency(26,1020)
1000L
>>> pi.set_PWM_frequency(26,1030)
1000L
>>> pi.set_PWM_frequency(26,1050)
1000L
>>> pi.set_PWM_frequency(26,1100)
1000L
>>> pi.set_PWM_frequency(26,1500)
1600L
>>> pi.set_PWM_frequency(26,1200)
1000L
>>> pi.set_PWM_frequency(26,1400)
1600L
>>> 

2 Answers 2

3

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()
1
  • Yes my stepper has a pulse/direction driver , so trying to understand your library , I should instantiate a wave , with 2 pulses (on and off , ) and a delay , something like for i in range(1): pi.wave_add_generic([ pigpio.pulse(1<<GPIO, 0, 200), pigpio.pulse(0, 1<<GPIO, (i+1)*200)]); wid[i] = pi.wave_create(); and then and then send them with wave chain command?? Commented Apr 27, 2016 at 0:07
2

researching joans python code , I managed to build a simple program to manage a ramp on a pulse/direction drver , it seems to work , I just need to add dynamic behavior so that it behaves according to mi stepper max acceleration , and fit it depending on the time I need it to work , but I consider that my question is answered , thanks Joan , the more I ask the more I like your amazing library

import time
import pigpio
import math as m 

GPIO=26
velocity = input('velocity (mm/s): ')
wid = [0]*10
perimeter = 40*m.pi
dist_p_step = perimeter/2000  #perimeter of mi roller , divided by steps needed for it to make 1 complete revolution
pulses = velocity/dist_p_step

num_ts = 2*pulses
ts = 1./num_ts       
us = ts*1000000       
pi = pigpio.pi() # Connect to local Pi.
print ts       
pi.set_mode(GPIO, pigpio.OUTPUT);
for i in range(10):
    pi.wave_add_generic([
       pigpio.pulse(0,1<<GPIO,us*(10-(i))),
       pigpio.pulse(1<<GPIO,0,us*(10-(i)))]);

    wid[i] = pi.wave_create();

pi.wave_chain([
    255, 0,                       # loop start
    wid[0],                       #run wave
    255, 1, 3, 0,                 #end loop , repeat 3 times
    255, 0,                       # loop start
    wid[1],                       #run wave
    255, 1, 3, 0,
    255, 0,                       # loop start
    wid[2],                       #run wave
    255, 1, 3, 0,
    255, 0,                       # loop start
    wid[3],                       #run wave
    255, 1, 3, 0,
    255, 0,                       # loop start
    wid[4],
    255, 1, 3, 0,
    255, 0,                       # loop start
    wid[5],
    255, 1, 3, 0,
    255, 0,                       # loop start
    wid[6],
    255, 1, 3, 0,
    255, 0,                       # loop start
    wid[7],
    255, 1, 10, 0,
    255, 0,                       # loop start
    wid[8],
    255, 1, 3, 0,
    255,0,
    wid[9],    
    255,1,255,0                   #end loop repeat 255 times

   ])

while pi.wave_tx_busy():
    time.sleep(0.1);
for wave in wid: 
    pi.wave_delete(wave)

pi.stop()
3
  • Well done with the code. One thing to note is that the current library is dimensioned for a maximum of ten loop counters per wave chain. It's the sort of limit you might reach if building a ramp.
    – joan
    Commented Apr 27, 2016 at 7:48
  • ok , si if I want a continous frequency , i should put pi.wave_chain(...) inside a loop? Commented Apr 27, 2016 at 14:43
  • If you want a continuous frequency make the last wave in the chain an infinite repeat, i.e. 255 0 last_wave_id 255 3
    – joan
    Commented Apr 27, 2016 at 14:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.