Controlling an X-Y Stage With a Joystick

Updated Feb 9, 2021



  • PCI-7334


  • LabVIEW


  • NI-Motion

This document contains step-by-step instructions on creating a motion control system that uses a joystick to move an X/Y stage. The purpose of this exercise is to highlight a real-world application of the NI 734x series of motion controllers and to introduce onboard programming. This session is not intended as an onboard programming training class, but you will come to understand the concept and benefits of onboard programming. This document assumes that you have already been exposed to the basic concepts of LabVIEW, and therefore focuses mostly on the motion control-specific VIs.

This session consists of two parts. In the first part, you build a complete LabVIEW VI for the NI PCI-7334 motion controller. The PCI-7334 is the NI low-cost stepper-only motion controller, which offers the flexibility and ease-of-use features found throughout the FlexMotion line of controllers. In the second part, you program for the PCI-7344 controller, which adds several advanced features including the ability to run onboard programs. The VI you create uses the onboard programming capabilities of the PCI-7344 motion controller to perform the same basic function as the first program, but takes advantage of a much higher degree of reliability and determinism.

Why Joysticks?

Joysticks are often used in industry as part of a training routine. Joysticks allow you to manually move a stage or other mechanical system through the desired points, which can be recorded for future motion generation. For many systems, this method is much more efficient and user-friendly than mathematically determining the required positions and trajectory parameters. In general, joysticks are good mechanisms to use whenever your application requires manual control and a graphical user interface like LabVIEW is not practical.


The two main ways to connect a joystick to your motion system are through the game port and through your motion controller.

The first method uses the standard game port available on most consumer PCs. This method involves no custom cabling, but requires some Windows programming for the motion controller to be able to read the joystick values. Additionally, onboard programming is not possible with this method, meaning reliability is reduced to that of the operating system of the host computer.

The second method of connectivity is accomplished by using the general-purpose analog inputs on your NI motion controller. You can also access the joystick inputs by connecting them to any of your motion controller’s peripheral motion I/O or general-purpose digital I/O lines. This example exercise uses the high-speed capture inputs operating as general-purpose digital inputs. This method allows the controller to directly read the joystick values and also facilitates the use of onboard programming.

For both sections of this exercise, the joystick is connected via the analog and high-speed capture inputs on the motion controller. Some simple custom cabling is required.

Joystick Connector Information

A standard joystick plug looks like this:

The necessary pinout connections are as follows:

Joystick OutputMotion Controller Input
Pin 1, + 5V+5V (available on UMI or drive)
Pin 2, button 1 (top button)Trigger 1
Pin 3, stick 1Analog Input 1 (Joystick Axis 1)
Pin 4 , GNDGND
Pin 6, stick 2Analog Input 2 (Joystick Axis 2)
Pin 7, button 2 (trigger button)Trigger 2
Pins 5, 8-15No Connect


Part I - Host Based Programming

Host-Based Programming

1. Start LabVIEW and open the JoyStage_Host_Frame VI.
2. The front-panel controls and indicators are already created for you. Open the VI diagram (Ctrl-E) to begin building your joystick application. Figure 1 shows the starting diagram.

Figure 1 - Template for Host Program

3. The first VI to place is Configure High-Speed Capture.flx. This VI configures the high-speed capture inputs as general purpose digital inputs to monitor the joystick buttons. The VI is found on the LabVIEW functions palette under Motion & Vision>>FlexMotion>>Motion I/O>> High-Speed Capture. Wire the inputs as shown in Figure 2, and create a constant for the Capture Mode and Axis Control.
Tip: To create a constant, right click on the VI terminal with the wiring tool and select Create>>Constant.
Place two of these VIs, one for Axis 1 and the other for Axis 2. Notice that they can share the Capture Mode constant.

Figure 2 - Added Configure High-Speed Capture.flx

4. Next, fill in the Case structure. The case structure is used to determine if joystick
calibration will occur.
a. For the True case, insert the pre-programmed sub-VI called To insert a sub-VI, click the item labeled "Select a VI" from the functions palette. Wire the sub-VI as shown in Figure 3.

Figure 3 - True Case

b. For the False case, simply wire the Board ID and Error from one side to the other and the Default X/Y values as shown in Figure 4.

Figure 4 - False Case

5. Set the motion-controller operation mode using the Set Operation Mode.flx, which is found on the functions palette under Motion & Vision>>FlexMotion>>Trajectory Control. Create constants for the axis inputs and the position mode. Again, notice that these two VIs can share the Position Mode constant. Now wire the Default X/Y values from the case structure, Board ID, and Error wires down to the while loop. Be sure to add all of the required wires as shown in Figure 5.

Figure 5 - Added Set Operation Mode.flx

6. Now, you will develop the While loop, which continuously monitors the joystick position and moves the axes appropriately. Place the Read High-Speed Capture Status.flx VI, which reports the status for all axes. To isolate just two axes (corresponding to our two joystick buttons), use the Unbundle By Name operation.
Tip: To easily unbundle the data, right-click on the output terminal and select Cluster Tools>>Unbundle by Name.
You will need to expand the unbundle operator by clicking and dragging on the corner of the icon using the pointer tool. This VI will use button 1 to determine if the axis should move at normal or fast velocity, and later will use button 2 to terminate the program. Wire the VI as shown in Figure 6.

Figure 6 - Added Read High-Speed Capture Status.flx

7. Place the Joy Read & VI, which reads the ADC values and scales them appropriately. Additionally, add the Select operation that chooses normal or fast speed. The Select function is found on the functions palette under Comparison. Wire all the inputs as shown in Figure 7.

Figure 7 - Added Joy_Read&

8. The next step is to load the velocities calculated by the VI in the previous step. Place two Load Velocity.flx VIs. These are found on the palette under Motion & Vision>>FlexMotion>>Trajectory Control. Create the necessary constants and wire as shown in Figure 8.

Figure 8 - Added Load Velocity.flx

9. Place the Start Motion.flx VI to initiate a move with the loaded parameters. It is found under Motion & Vision>>FlexMotion>>Start & Stop Motion. Create the Axis Control and Axis/VS Map constants, then wire appropriately. As usual, create the constants by right-clicking the appropriate terminals and selecting Create>>Constant. Refer to Figure 9.

Figure 9 - Added Start Motion.flx

10. To prevent the while loop from running forever, you must have a way to stop it. The STOP button on the front panel and one of the joystick buttons are used to accomplish this. You also want the loop to terminate if the VI encounters an error. To check for errors, right-click the Error Out terminal on the Start Motion.flx VI and select Cluster Tools>>Unbundle by Name. Wire the Error Out to this unbundle operator. Next, place a boolean operator to monitor all three cases for stopping the loop. Use the Compound Arithmetic operator found on the Boolean palette. You will need to expand the operator for three inputs, then right-click and select Change Mode>>OR. This will cause the loop to terminate when the user presses the button on the joystick, when they press the button on the VI Front Panel, or when an error occurs. Wire all the inputs to the OR as shown in Figure 10.

Figure 10 - Added loop control elements

11. The final addition to the while loop is a delay. It is good programming practice to place a small delay in any loop to prevent overwhelming the host system and unnecessarily attacking the controller with continuous messages from the host. The Wait Until Next ms Multiple VI is found on the functions palette under Time & Dialog. A 100-millisecond delay should be enough to avoid problems with the host while still being very responsive to joystick movements. Add the VI as shown in Figure 11.

Figure 11 - Added Wait Until Next ms Muliple for loop delay

12. Now add The Stop Motion.flx VI (Motion & Vision>>FlexMotion>>Start & Stop Motion), which will stop the stage once you exit the while loop.
Figure 12 shows this VI added just to the right of the While Loop. Notice that you can re-use the Axis Control and Axis/VS Map constants from the Start Motion.flx VI.

Figure 12 - Added Stop Motion.flx

13. Finally, add the VI Motion Error Handler.flx. It is good program practice to always end a program with an Error Handler VI. Doing so will alert you at run-
time that an error condition has been detected. You can find the Motion Error Handler.flx VI under Motion & Vision\FlexMotion\Error & Utility. Your complete program should look like Figure 13.

Figure 13 - Added Motion Error Handler.flx. Completed Program


Running the VI:

1. Be sure the cable connected to the MID-7604 Power Drive is the one labeled "PCI-7334".
2. Verify the correct Board ID is entered on the front panel. Use Measurement & Automation Explorer (MAX) to find the Board ID of your PCI-7334.
3. Be sure Calibrate Joystick is enabled on the Front Panel, or run the VI CalibrateJoy manually and copy the values reported to the Default X/Y Limits
4. You can adjust the values for Slow Speed, Fast Speed and DeadBand. The speeds are loaded in steps/sec and represent the maximum velocity of the stage motors. The DeadBand is a threshold value such that the motors will be commanded a velocity of exactly zero if the joystick commands a value that is just close to zero.
This will prevent the stage from "creeping" when the joystick is in the center position, but not exactly at the calibrated center value.
5. If you reach a limit switch by moving the stage to its extreme range of motion, the corresponding axis will be halted. You may need to restart the program while holding the joystick in the opposite direction of the limit switch. It is best to avoid moving the stage all the way to its limits.


Part II - Onboard Programming

Onboard Programming

In this section you are going to build a program that performs the same function as the one in part I, but it will run as an onboard program. Onboard programming is an advanced feature available only on the high-performance 7344 line of controllers.

1. Start LabVIEW and open the VI named The front panel controls and indicators have already been created for you. Open the diagram to begin building your onboard joystick application. Your diagram should look like Figure 14.

Figure 14 - Template for Onboard Program

2. Just as in host-based programming, start by placing some VIs to configure the controller. Place the Configure High-Speed Capture.flx and Set Operation
Mode.flx VIs as shown in Figure 15, and create the necessary constants. Notice that you can share several constants and use the Resource Out of some VIs.

Figure 15 - Initial Configuration - Added Configure High-Speed Capture.flx and Set Operation Mode.flx

3. Now, place the VIs that will actually execute on the controller. When doing onboard programming, you must start your program with the Begin Program
Storage.flx VI. This signals to the software that the remaining VIs will be an onboard program to download to the board. The VI is found on the palette under Motion & Vision>>FlexMotion>>Onboard Programming. Place the VI and wire as shown. You will need to create a constant for the program number. Refer to Figure 16.

Figure 16 - Added Begin Program Storage.flx

4. Next, place This VI loads constants to onboard variables used for scaling the joystick values. Place and wire the VI as shown in Figure 17.

Figure 17 - Added

5. Place a label that serves as the beginning of the execution loop. Later, you will place a jump VI to implement the complete loop. This will perform the same function as the while structure that you used in host programming. To place the label, use the Insert Label.flx VI found on the palette under Motion & Vision>>FlexMotion>>Onboard Programming. Number the label "1" as shown in Figure 18.

Figure 18 - Added Insert Label.flx

6. Now you are within the loop, and will place the VIs that repeatedly monitor the joystick and command the stage to move. Read_ADC& reads the ADCs, performs the necessary scaling, and initiates a move at the commanded velocity. This VI does most of the fundamental low-level work involved in writing an onboard program. You can view its contents by double-clicking the VI and pressing Ctrl-E to bring up the diagram.

Figure 19 - Added Read ADC &

7. The Read High Speed Capture Status.flx VI determines if the STOP button is being pressed on the joystick. Place it as shown in Figure 20. Notice the Return Vector is 1, which means data will be returned to onboard variable 1 rather than to the host.

Figure 20 - Added Read High Speed Capture Status.flx

8. After reading the button status, your VI must compare the value returned from Read High Speed Capture Status.flx to the known idle status you previously stored in onboard variable 2. Use the onboard AND Variables.flx VI, found on the Onboard Programming>>Data Operations palette as shown in Figure 21. Notice you can share the Variable Number constant from the previous VI.

Figure 21 - Added And Variables.flx

9. The Jump to Label on Condition.flx VI is a jump statement that only executes if the joystick STOP button is not being pushed. This VI is found on the Onboard Programming palette. Place and wire it as shown in Figure 22. Again, you can share the Label Number constant. This is good practice, especially in larger onboard programs when it can become difficult to keep track of all the label numbers.

Figure 22 - Added Jump to Label on Condition.flx

10. Now you are out of the loop. In case the user stopped the program while the stage was moving, you must halt-stop the stage. To do this, place the Stop Motion.flx VI from the Start & Stop Motion palette as shown in Figure 23, then create constants for Stop Type and Axis Map.

Figure 23 - Added Stop Motion.flx

11. The onboard section of the program is now complete, so place the End Program Storage.flx VI as shown in Figure 24. This VI is found on the Onboard Programming palette. Everything between Begin Program Storage.flx and End Program Storage.flx is downloaded to the controller and runs independent of the host computer. As with label numbers, program number constants should be shared whenever possible.

Figure 24 - Added End Program Storage.flx

12. Your onboard program is now complete and will download to your motion controller when you execute the VI. The final VIs you place tell the software to execute the onboard program immediately after it is downloaded and check for errors. Place the Run Program.flx VI from the Onboard Programming palette and Motion Error Handler.flx from the Error & Utility palette. Use the Resource Out terminal from the End Storage VI as the program number for the Run Program VI. Refer to Figure 25 for the completed VI.

Figure 25 - Added Run Program.flx and Motion Error Handler.flx. Completed Program


Running the VI

1. Be sure the cable connected to the MID-7604 Power Drive is the one labeled "PCI-7344".
2. Verify the correct Board ID is entered on the front panel. Use Measurement & Automation Explorer (MAX) to find the board ID of your PCI-7344.
3. Run the VI and verify the reported values match the X and Y limits on the front panel of your onboard program.
4. You can adjust the values for Slow Speed, Fast Speed and DeadBand just as in the host-based program.
5. If a limit switch is reached while running the onboard program, the program pauses and must be restarted. Avoid moving the stage to its extreme ranges of motion.
6. MAX has built-in capabilities that make working with onboard programs easier. For example you can view what programs are currently on the board, start, stop or pause programs, or even save programs to Flash memory for permanent storage. You can access these functions from the Onboard Memory Manager tab under the panel named My System>>Devices and Interfaces>>PCI-7344>>Device Resources.
7. Notice that you can close LabVIEW and your joystick-controlled stage continues to function. In fact, the entire program is now executing independent of the Windows environment.

Congratulations, your onboard program is complete!