06-29-2019 04:07 PM
Hello,
I have a problem using nidaqmx digital output to control a stepper motor in Python. I have read through the Python documentation (http://nidaqmx-python.readthedocs.io/en/latest/index.html ) and this example (https://github.com/ni/nidaqmx-python/blob/master/nidaqmx_examples/do_sw_timed.py) already, but I am running into issues getting the stepper motor to rotate. So far it seems like the digital output is being sent to the motor, but the motor is only vibrating and not rotating.
System:
Windows 7, Python 3.7, NI USB-6009
The code:
import nidaqmx import time from nidaqmx.constants import ( LineGrouping) with nidaqmx.Task() as task: task.do_channels.add_do_chan('Dev1/port1/line0:3') task.start() while True: task.write([8,0,0,0]) time.sleep(.002) task.write([0,8,0,0]) time.sleep(.002) task.write([0,0,8,0]) time.sleep(.002) task.write([0,0,0,8]) time.sleep(.002)
When I run the code, the stepper motor will vibrate but it will not rotate like I want it to. Any suggestions to fix this problem? I have already tried changing the length of the pause from .002 to .02 to .2 (and values in between). I have also tried writing different values of bits such as [8,0,8,0] and [0,8,0,8]. Changing the length of the pause will change how frequently it vibrates, but I cannot get the motor to actually rotate. I assume it is an issue with what bits I am writing to the task, because the digital output works.
For reference, here is a version of the code in matlab that works like it is supposed to on the same computer/system:
clear all close all clc pt=2/100; s=daq.createSession('ni') %% addDigitalChannel(s,'Dev1','Port1/Line0','OutputOnly'); addDigitalChannel(s,'Dev1','Port1/Line1','OutputOnly'); addDigitalChannel(s,'Dev1','Port1/Line2','OutputOnly'); addDigitalChannel(s,'Dev1','Port1/Line3','OutputOnly'); n=0 while(n<100) outputSingleScan(s,[1 0 0 0]); pause(pt) outputSingleScan(s,[0 1 0 0]); pause(pt) outputSingleScan(s,[0 0 1 0]); pause(pt) outputSingleScan(s,[0 0 0 1]); pause(pt) n=n+1 str='loop' end clear all close all
Thanks in advance, any advice is appreciated.
Solved! Go to Solution.
07-01-2019 09:00 PM - edited 07-01-2019 09:02 PM
Hi GoBears1,
So glad to see you are using the nidaqmx Python module. I love playing around with it. Let me take a shot at explaining what could be going on even though I am not sure how you are supposed to control the stepper motor.
So task.write([8,0,0,0]) will write multiple samples to the DAQ device and return after generating all the samples. The nidaqmx documentation says, "If the task uses on-demand timing, this method returns only after the device generates all samples." The example you provided shows that the write method returns the integer four, meaning four samples were written, and it requires autostart to be set to true or the task to be started for the write to work. You can write to tasks before starting them when you have timing configured, but you can't do waveform generation with the USB-6009. I am not sure what it means to write multiple samples to a task which uses on-demand timing. With this type of timing, you normally write to the channel when you want to update it. I imagine it runs through the samples very quickly and holds the last value written to it. For the first array, there will be a high on line three and then a low on all four lines. Essentially the same thing will happen for the other arrays except the last one, which may hold high on line three until the sleep is over.
If I had to rewrite the Python code to mimic the other code, I would do something like this.
import nidaqmx import time pt = 2/100 with nidaqmx.Task() as task: task.do_channels.add_do_chan('Dev1/port1/line0:3') n = 0 task.start() #This should be optional while n < 100 : task.write(1) time.sleep(pt) task.write(2) time.sleep(pt) task.write(4) time.sleep(pt) task.write(8) time.sleep(pt) n = n + 1
I am more confident that the integer write will work than any other method. I would think that [True, False, True, False] would write a boolean value to each line like it does in LabVIEW, but running the example code indicates that it is treated as four samples instead of one to each line. Let me know if you are still having issues, and I can try to replicate it myself as I used simulated hardware to test everything. You can also route the output into an input to test the code for the desired behavior.
Best,
David F.
Technical Support Engineer
National Instruments
www.ni.com/support
07-16-2022 03:59 AM
I got the code to work in the pretty much the original form. The correct task.do_channels.add_do_chan() declaration is: task.do_channels.add_do_chan("Dev1/port1/line0:3", line_grouping=LineGrouping.CHAN_PER_LINE), the" line_grouping=LineGrouping.CHAN_PER_LINE" was missing. After adding the missing declaration, the booleans worked fine. Verified on a NI USB-6501 with an oscilloscope.
Full code:
#Imports
import nidaqmx
import time
import msvcrt
from nidaqmx.constants import LineGrouping
#Stepper Motor Control
with nidaqmx.Task() as task:
task.do_channels.add_do_chan("Dev1/port1/line0:3", line_grouping=LineGrouping.CHAN_PER_LINE)
task.start()
while True:
task.write([True,False,False,False])
time.sleep(.05)
task.write([False,True,False,False])
time.sleep(.05)
task.write([False,False,True,False])
time.sleep(.05)
task.write([False,False,False,True])
time.sleep(.05)
if msvcrt.kbhit(): # Check the keyboard and exit if any key pressed.
key_stroke = msvcrt.getch()
#print(key_stroke) # will print which key is pressed.
if key_stroke:
break