rattidotcom
Posts: 13
Joined: Tue Jan 29, 2019 12:30 am

Send number of pulses with Pigpio

Mon Jun 10, 2019 3:43 pm

Hello,
I'm trying to swich from RPi.GPIO to Pigpio to controll two Stepper Motors with DRV8825 Driverchips. Until now I made for loops to move ballscrews, for example: for i in range (200) # 200 Impuls = Motor makes 1 rotation.
The problem for me with RPi.GPIO is that I have to use time.sleep between every pulse and with that I can't reach high RPM.
With the following code the Stepper starts spinning and stops after 2 seconds.

Code: Select all

#18 = GPIO pin that is wired to the DRV8825

def Fahrt():
    pi.hardware_PWM(18, 1000, 128)
    time.sleep(2)
    pi.hardware_PWM(18, 0,0)
Is there a command to send a PWM Signal with for example 200 "high" pulses?

User avatar
joan
Posts: 14024
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Send number of pulses with Pigpio

Mon Jun 10, 2019 3:54 pm

If you want to send a specific number of precisely timed pulses you need to use a wave chain.

Basically you create a wave with a single pulse (e.g. 5µs on 20µs off) and send that 200 times with a wave chain. The maximum pulse rate is 500kps (1µs on, 1µs off).

What pulse do you want, which GPIO, and how many?

rattidotcom
Posts: 13
Joined: Tue Jan 29, 2019 12:30 am

Re: Send number of pulses with Pigpio

Mon Jun 10, 2019 4:12 pm

Ok thanks I will test this.
Right now I set it to 1000 Pulses per second. But I want to ramp it up to 1600. Thats the maximum for my Stepper, everything above and the Stepper is to weak to move the Ballscrew.

GPIO18 on BCM Layout and only one Motor at the same time.

User avatar
joan
Posts: 14024
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Send number of pulses with Pigpio

Mon Jun 10, 2019 4:31 pm

Have a look at

Code: Select all

G=18

pigs m $G w # set GPIO in mode OUTPUT

pigs wvag $((1<<G)) 0 10 0 $((1<<G)) 615 # 10 us on / 615 us off

pigs wvcre # create wave (first will have id 0)

pigs wvcha 255 0 0 255 1 200 0 0 # send wave id 0 200 times

rattidotcom
Posts: 13
Joined: Tue Jan 29, 2019 12:30 am

Re: Send number of pulses with Pigpio

Mon Jun 10, 2019 5:11 pm

Thanks for the code but I don't get it to work.. Are you sure this is for Python3.5? :D :D
I get a Syntax Error at the "m" in the first line.

PS: If you are the Guy who wrote this hole thing, Thanks for the good work!
My fast and smooth running Stepper Motor is also very grateful ;)

User avatar
joan
Posts: 14024
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Send number of pulses with Pigpio

Mon Jun 10, 2019 5:17 pm

That was a command line example using the pigs utility. You enter those commands in a terminal window.

You need to translate those commands into the appropriate Python (i.e. wave_add_generic, wave_create, wave_chain etc.).

rattidotcom
Posts: 13
Joined: Tue Jan 29, 2019 12:30 am

Re: Send number of pulses with Pigpio

Mon Jun 10, 2019 10:13 pm

So i tried my best to put it all in a script. This is what i've got but I don't know how to continue

Code: Select all

#!/usr/bin/env python

import RPi.GPIO as GPIO
import pigpio

GPIO.setwarnings(False) 

pi = pigpio.pi()
pigpio.pi("soft", 8888)

GPIO.setmode(GPIO.BCM)
GPIO.setup(18,GPIO.OUT)
GPIO=18

#pigs wvag $((1<<GPIO)) 0 10 0 $((1<<GPIO)) 615 # 10 us on / 615 us off
pi.wave_add_generic((1<<GPIO, 0, 10, 0, ))((1<<GPIO, 615))


#pigs wvcre # create wave (first will have id 0)
pi.wave_create()


#pigs wvcha 255 0 0 255 1 200 0 0 # send wave id 0 200 times
pi.Wave_chain ((255, 0, 0, 255, 1, 200, 0, 0,))

It gives me the Error:

Code: Select all

Traceback (most recent call last):
  File "/home/pi/Schreibtisch/RPIPWM.py", line 16, in <module>
    pi.wave_add_generic((1<<GPIO, 0, 10, 0, ))((1<<GPIO, 615))
  File "/usr/lib/python3/dist-packages/pigpio.py", line 2117, in wave_add_generic
    ext.extend(struct.pack("III", p.gpio_on, p.gpio_off, p.delay))
AttributeError: 'int' object has no attribute 'gpio_on'
I hope you can help me again..

rattidotcom
Posts: 13
Joined: Tue Jan 29, 2019 12:30 am

Re: Send number of pulses with Pigpio

Tue Jun 11, 2019 12:50 pm

UPDATE! With the following Code the Stepper Motor makes 2000Steps. But I can't get over 2730 Steps with this for loop :?
I get this Error.. I copied the for loop under the first one with a small time delay, to get in summary over 2730 but that don't work too and its really ugly..

Code: Select all

Traceback (most recent call last):
  File "/home/pi/Schreibtisch/RPIPWM.py", line 26, in <module>
    pi.wave_add_generic(pulse)
  File "/usr/lib/python3/dist-packages/pigpio.py", line 2120, in wave_add_generic
    self.sl, _PI_CMD_WVAG, 0, 0, len(pulses)*12, extents))
  File "/usr/lib/python3/dist-packages/pigpio.py", line 1006, in _pigpio_command_ext
    sl.s.sendall(ext)
ConnectionResetError: [Errno 104] Connection reset by peer

Code: Select all

#!/usr/bin/env python

import RPi.GPIO as GPIO
import pigpio

GPIO.setwarnings(False)
pi = pigpio.pi()

GPIO.setmode(GPIO.BCM)
GPIO.setup(18,GPIO.OUT)
GPIO=18

pulse=[]
pi.wave_clear()
for i in range(0,int(2000)):
    # GPIO18 ON
    pulse.append(pigpio.pulse(1<<GPIO, 0, 350))     
    # GPIO18 OFF
    pulse.append(pigpio.pulse(0, 1<<GPIO, 350))

pi.wave_add_generic(pulse)
pulse_waveform_id = pi.wave_create()         
pi.wave_send_once(pulse_waveform_id)


User avatar
joan
Posts: 14024
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Send number of pulses with Pigpio

Tue Jun 11, 2019 1:35 pm

You really need to use a wave chain. It can handle pulse loops. The way you are doing it is fine but you do hit a resource limit (each pulse uses up some limited memory).

rattidotcom
Posts: 13
Joined: Tue Jan 29, 2019 12:30 am

Re: Send number of pulses with Pigpio

Tue Jun 11, 2019 9:19 pm

Ok I understand.. I hope this way is the right way to handle this with a wavechain:
My Steppermotor turns smoothly with no jitter or something. But am I right that the smallest amount of steps is 256?
I've got this in the last line of the first for-loop. I tried to multiply with a decimal Number, but it needs an Integer..

Code: Select all

import pigpio
import time
import RPi.GPIO as GPIO
GPIO.setwarnings(False) 

pi = pigpio.pi()
GPIO.setmode(GPIO.BCM)
GPIO.setup(18,GPIO.OUT)
GPIO.setup(12,GPIO.OUT)
GPIO=18
#####

wid=[0]*1
for i in range(1):
   pi.wave_add_generic([
      pigpio.pulse(1<<GPIO, 0, 10),#  microSeconds on
      pigpio.pulse(0, 1<<GPIO, 2500)]);#  microSeconds off

wid[i] = pi.wave_create();

pi.wave_chain([
    255, 0,# Loop Start  	Identify start of a wave block
    wid[0],         # Waveblock
    255, 2, 0x64, 1,     # Delay delay x + y*256 microseconds
    255, 1, 0, 1,             # Loop Repeat x + y*256 times
])

for i in range(1):
   pi.wave_delete(wid[i])

pi.stop()
]

User avatar
joan
Posts: 14024
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Send number of pulses with Pigpio

Tue Jun 11, 2019 9:46 pm

You don't need an additional delay in the wave chain (the 255 2 command) as the wave already has a delay (the off period).

Say you want to loop REPEAT times (I assume 1 <= REPEAT <= 65535).

Then set x = (REPEAT&255) and y = ((REPEAT>>8)&255) then

255 1 x y will loop REPEAT times.

rattidotcom
Posts: 13
Joined: Tue Jan 29, 2019 12:30 am

Re: Send number of pulses with Pigpio

Wed Jun 12, 2019 1:01 am

You mean something like this? :D It works, thank you so much for your help!!! I also want to change the direction of the Motor. To do that i normaly just need to set a GPIO Pin high that is wired to the Direction Pin on the Driverchip. I tried pi.write(12,1) on the beginning of the loop and (12,0) at the end, but the Motor loose Steps with this method. So I generate a pulse with 10microseconds in pi.wave_add_generic. It works fine but is this right way? :?

Code: Select all

REPEAT = 200
x=(REPEAT&255)
y=((REPEAT>>8)&255)

Code: Select all

 pi.wave_add_generic([
         pigpio.pulse(1<<DIR, 0, 10),#  direction Pin On  
         pigpio.pulse(1<<GPIO, 0, 10),# for x microSeconds on
         pigpio.pulse(0, 1<<DIR, 10),#Direction Pin Off
         pigpio.pulse(0, 1<<GPIO, 1500)]);#  for x microSeconds off

User avatar
joan
Posts: 14024
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Send number of pulses with Pigpio

Wed Jun 12, 2019 8:23 am

That seems okay, but it should have worked if you set it before and after the call to wave_chain. It wouldn't work if you set it while the wave_chain is running.

Note that wave_chain returns control to Python as soon as it is started. The wave_chain can take a long time to complete (e.g. 60000 seconds if you repeat a one second pulse 60000 times). So the following might not work if the direction depended on gpio X.

Code: Select all

set gpio X high
wave_chain
set gpio X low
In that situation you would need to see if the wave had finished, e.g.

Code: Select all

set gpio X high
wave_chain
while wave_busy:
   time.delay(0.01)
set gpio X low
So that while the wave chain is active you test for completion every 1/100th of a second.

rattidotcom
Posts: 13
Joined: Tue Jan 29, 2019 12:30 am

Re: Send number of pulses with Pigpio

Thu Jun 13, 2019 12:07 am

I don't get the wave_busy command to run. It always gives me the Error" module 'pi' has no attribute 'wave_busy'". I tried it with pi.waveBusy and
pi.wave_busy and so on..
My next goal is to set a function that calls some defenitions in a row. I wrote some functions with differt microseconds pause and differt Steps like make 200 steps with 700ms pause between.
I tried this: But like you said before, the module gives the chain to python and with this function the second command starts immediately after the first one. It works when I put time.sleep(0.2) between them, but the sleep command must be exactly as long as it takes to make for example 200 Steps with 750us pause. So I think your wave_busy function is the right thing to handle it? So the next function will start right after the delay of the "wave busy time delay". Please don't think that I don't try this all by myself, I never learned programming in school :roll:
So could you please give me an example for the wave_busy command in "script" language?

Code: Select all

def vorzuru():
    vor750()# 200Steps CounterClockwise with 750us pause
    zuru()#200 Steps Clockwise with 500us pause
    


rattidotcom
Posts: 13
Joined: Tue Jan 29, 2019 12:30 am

Re: Send number of pulses with Pigpio

Thu Jun 13, 2019 11:18 am

Don't know how I could overlook that... Thanks it works perfectly!! And thanks for answering all the other questions that might seem easily to you! :D

Code: Select all

def vorzuru():
    vor750()# 200Steps CC with 750us pause
    while pi.wave_tx_busy():
        time.sleep(0.01)
    zuru()#200 Steps C with 500us pause

rattidotcom
Posts: 13
Joined: Tue Jan 29, 2019 12:30 am

Re: Send number of pulses with Pigpio

Sun Jun 16, 2019 11:05 am

hello,
is it possible to run to wave chains simultaneously? Or run a wave chain on one GPIO and pi.hardware_PWM(GPIO, Frequency, Dutycicle) on another GPIO?
I tried threading but the two commands run one after another.. My goal is that Stepper1 starts turning, then Stepper2 is moved by some wave chains and at the end Stepper1 turns off.

User avatar
joan
Posts: 14024
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Send number of pulses with Pigpio

Sun Jun 16, 2019 11:41 am

You can only have one wave chain running at a time. You can't use a wave chain and the hardware_PWM function at the same time.

You can control multiple GPIO in a single wave chain. It becomes trickier to control two steppers but is possible (software isn't always easy).

Can you give any concrete examples of what you want?

rattidotcom
Posts: 13
Joined: Tue Jan 29, 2019 12:30 am

Re: Send number of pulses with Pigpio

Sun Jun 16, 2019 12:35 pm

yes of course. This is the way I run my Steppermotor attached to a ballscrew:

Code: Select all

#First stage with a low RPM 
def vor():
   wid=[0]
   for i in range(1):
      pi.wave_add_generic([
         pigpio.pulse(1<<STEP2, 0, 1350),#  microSeconds on
         pigpio.pulse(0, 1<<STEP2, 20)]);#  microSeconds off
   wid[i] = pi.wave_create();
   REPEAT = 100 #Total Steps 
   x=(REPEAT&255)
   y=((REPEAT>>8)&255)
   pi.wave_chain([
       255, 0,       # Loop Start 
       wid[0],       # Waveblock
       255, 1, x, y, # Loop Repeat = REPEAT
   ])
   
#Second Stage with a higher RPM   
def vor1():
   wid=[0]
   for i in range(1):
      pi.wave_add_generic([
         pigpio.pulse(1<<STEP2, 0, 900),#  microSeconds on
         pigpio.pulse(0, 1<<STEP2, 20)]);#  microSeconds off
   wid[i] = pi.wave_create();
   REPEAT = 1200#Total Steps 
   x=(REPEAT&255)
   y=((REPEAT>>8)&255)
   pi.wave_chain([
       255, 0,       # Loop Start 
       wid[0],       # Waveblock
       255, 1, x, y, # Loop Repeat = REPEAT
   ])
   
   
   #Start at low Speed and then the higher Speed
   def move():
      vor()
      vor1()
  
   
So i tried something like.

Code: Select all

def move():
      pi.hardware_PWM(13, 1000, 128)#PWM on GPIO13
      vor()
      vor1()
But like you already said this is impossible. What I want to do is in this order:

1.Send PWM to the Steppermotordriver1(GPIO13) so the Stepper1 turns "infinite". One Frequency is enough the Motor don't need to do high
RPM.
2.Send PWM to the Steppermotordriver2(GPIO18) with some stages to achieve a Higher RPM. For Example 200 Steps 600hz = 3 Rotations per
Second and then 2000 Steps at 1000hz. After this I only need to set GPIO12(DirectionPin on the Driveboard) permanent on High and repeat
these two Steps contrariwise to move the ballscrew backwards to its Home Position.
3.After this the Stepper1(GPIO13) is still turning until the User presses a Button or a Switch, to stop the set the PWM on GPIO13.
This may not sound very complicated at all for you, but for it is :oops:
Note to Step2.: It does not have to be a PWM Signal necessary. I already got good results with the RPi.GPIO Module to run Steppers at low RPM,with (GPIO18,High), (time.sleep(0.001), (GPIO18,Low),.... But your Module with the Hardware PWM is much better!!

Return to “Automation, sensing and robotics”