LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Running two stepper motors at the same time from one port

Solved!
Go to solution

Hello,

 

I have to run two motors at the same time - one used to move a linear ball screw and one to turn a grip. I am doing tension and torsion testing on small wires, but tension and torsion have to be done at the same time. I also have to build in the ability for each motor to take multiple steps, ie. have a motor take x number steps at y velocity and then move x number of steps at z velocity. Both motors need to be able to do this. However, I am having problems getting the motors to run at the same time and to take all the steps. The motors are connected to two RMS Technologies R356 controllers. Both of the controllers are then connected to one RS485 to USB converter card, and that card is connected to one of the USB ports in the computer. Currently, I pass an array of commands to two for loops each containing VISA read and writes. I've attached the vi to look at. All of the timing stuff in the code is because a new command cannot be sent to the controller before the motor is done executing the previous command. If commands are sent right after one another, the controller will only execute the first command and then return with an error. 

 

Does anyone have a suggestion as to what I am doing wrong?

 

Thanks in advance for any help. 

0 Kudos
Message 1 of 20
(4,609 Views)

You should not split the VISA refnum wire between two loops.  When one of your for loops finishes faster than the other, VISA Close executes, which closes the serial port and makes it unavailable to the other for loop.  Instead, structure your code so that a single instance of VISA Write sends commands to both motors.  For example, you could put the VISA Write in one loop, and then have two parallel loops, one per stepper motor.  Each time you need to send a command to one of the motors, put that command into a queue.  The VISA Write loop would wait on the queue, dequeueing commands as it receives them and sending them to the motors.

 

EDIT: Also, you should avoid local variables where a shift register would be sufficient.  If you put a shift register in your for loop you can initialize it directly, which replaces your local variable, removes the need for the sequence structure, and results in cleaner, better code.

Message Edited by nathand on 06-05-2009 04:44 PM
0 Kudos
Message 2 of 20
(4,597 Views)

Hi nathand,

 

Thanks so much for your response. To be honest, I have only been programming in LabView for about 4 weeks so I'm a bit confused as to what you are saying. I've never used queue and dequeueing commands before. It sounds like it would work though. Do you think you'd be willing to help me out with the actual code? I looked at the example that LV provided and I've attached my first attempt. I realize I have other problems with this code (the conditional terminal on my while loop is not connected to anything, for one). One of my main problems is that I don't quite understand the queueing commands. I am planning on doing more research on NI's site tomorrow, but do you think you could also give me a little more direction? I've been trying to get this working for a couple weeks now so I'm getting a bit impatient. 

 

Thanks! 

0 Kudos
Message 3 of 20
(4,585 Views)

Your while loop won't run until your lower For loop finishes because the dependency of that loop on the dataflow of the queue wire.

See the attached file which will show you how to get a bit closer to what you want to do.

0 Kudos
Message 4 of 20
(4,581 Views)

Hi,

 

I am still having problems running the motors. The first step I am sending will execute on both motors at the same time, but then the subsequent steps send back a command overflow error. This means that the VISA write command is still sending the next command before the motor is done executing the previous command. Any ideas as to what I'm doing wrong?

 

Thanks!

0 Kudos
Message 5 of 20
(4,531 Views)

How are you determining when the motor is done executing its command?  How long does it normally take?  Right now you are only pacing your commands based on the wait timer in each For loop.  But those for loops are running simultaneously, so you would be getting 2 commands queued up depending on the relative timing of those two loops.  The only thing basing the consumer loop where the commands are being written out is how long it takes to read back 50 bytes, or the timeout of the VISA read which is 10 seconds by default.

0 Kudos
Message 6 of 20
(4,523 Views)

Hi Ravens Fan,

 

The way I was doing it was by calculating the time it would take each command to execute. The for loop would wait the amount of time it takes to execute one command before sending out the next one. Therefore, I could see a tension and a torsion command getting queued up at the same time, which should theoretically be ok because the commands are being sent to two different controllers. I don't understand why though a command is being queued and sent to one motor before that motor is done. That's where I'm running into problems. 

 

However, a little bit ago I posted on this forum about another way to find out if the motor has completed the task and I think you responded. It was about scanning a string in a VISA read for a 66. The controller/motor company says that if you send the motor a command like /1P1000p66R it should send a 66 back when it has moved 1000 steps. I had problems with this because the controllers/motors send a string back right away and don't keep querying for another response. I think that this would be a better way than the timing option I talked about above though so I'm going to give it another shot. I wrote a new vi and have attached it. These are the steps I'm hoping it will take:

 

1. Send both motors their respective first command. 

2. When the tension motor sends out a 66, send it a new command. When the torsion motor sends out a 67, send it a new command. 

3. Repeat step 2 until all the commands have been sent to each motor. 

 

Right now, I don't know how to get the queue to enqueue the corrrect command after the VISA read finds a 66 or 67.  I can work on it though. Any hints? Also, do a need shift registers on the queue wires in the for loops?

 

Thanks again!

0 Kudos
Message 7 of 20
(4,517 Views)

That does sound familiar.

 

You basically need to set up a communication mechanism back to the enqueueing loops.  I'll list 3.

 

1.  Another queue or notifier for messages back to the producer loops.  You'd need one for each loop.  So if you get a 66 in response, put a true back in the notifier or queue that is associated with that loop.  Likewise with a 67 for the other loop.

2.  Action engine.  Have an action engine (see Ben's nugget) that stores the status of each controller.  When it gets a 66, it changes the status of that controller from "running" to "waiting for command".  The producer loops continually monitor the action engine for their particular control waiting for the "waiting for command".  Once it sees it, it pops another message into the queue and sets the status to "running"

3.  Local variables.  These can lead to race conditions, but if you are careful, they will work just fine.  Similar to #2.  The enqueue commands sets a boolean to false and enqueues the command.  The consumer loop set the boolean to true when it sees a 66, otherwise it does nothing.  (Another boolean is associated with 67 and the other loop).  The producer loop waits for its boolean to become true again and then it resets it to false and enqueues the next command.  It is basically a handshaking mechanism.

 

Watch out for your loops.  You have the big while loop wrapping everything up again.  It won't iterate for anothe write or read until the read while loop is done and both For loops have completed all of their steps.

 

You may want to rethink this into a state machine architecture and combine both of your producer loops into a single while loop.  States would be waiting for response, enqueue motor #1, enqueue motor #2, .....

0 Kudos
Message 8 of 20
(4,512 Views)

I tried the state machine method. This vi doesn't seem to work, but this is the first state machine I've written in LV so it's bound to have errors. The one problem I see now is how to get the first commands to the motor. Any suggestions?

 

Thanks.

0 Kudos
Message 9 of 20
(4,504 Views)

I'm not too clear on exactly what you are trying to accomplish or some of the details.

 

Are there equal number of torsion and tension steps?

Is there a pairing between a torsion and tension?  For example, you want to tension and torsion simultaneously, but those two together make a complete step?

Do you want to wait until both the torsion and tension have completed before moving on to the next torsion/tension pair?

Is there any time delay you want to hold at before moving on to the next step.

 

When working with state machines, it is important not only to define the states, but also the logical stepping from one state to the next, or alternatives based on conditions.  It could be flowchard, but sometimes people call them state charts.

 

Right now your latest posting has goes to "Write to Motor" event though and will wait there forever because there is nothing in the queue to write out through the VISA port.

Let's assume your first state would happen to be Enqueue Tension (in order to get something in the queue), you will actually queue up all your tension commands at once with the For loop.  Then i will be 1 less than the size of the array it always will be because for an array size n, i will go from 0 to n-1 on each iteration.  So your false case will run and you will go to "Write to Motor".  Write to Motor will run and dequeue the first command then go to Waiting for Response.  Waiting for response will iterate through the while loop until 66 or 67 comes back.  I assume only 66 will come back for tension since you have yet to write a torsion command.  Once that comes back, it will go to Enqueue Tension again and insert a whole other series of commands.  Then go back to write Motor and will take out the 2nd queue element from the first set of commands your wrote.  It will stay in a Tension mode and the Queue will grow endlessly putting in a whole new series for each element that you dequeue.

'

A state machine is the way to go, but I can't really sketch one out for you because I'm not sure exactly how your applications is supposed to work.  If a tension and torsion command are paired together,  perhaps you should just queue them together and write them out at once.   But the key thing is to sketch out on paper your application and flowchart exactly how the program should progress from step to step.

 

 

PS:  One other thing, make sure you wire the queue reference wire through all states.

 

0 Kudos
Message 10 of 20
(4,497 Views)