Skip to content

NISystemsEngineering/cRIO-Python-AI-Workflows

Repository files navigation

NI cRIO Python Development Workflows

This repository demonstrates four development workflows for the National Instruments cRIO platform using Python. Each workflow builds on the previous, progressing from pure local simulation through hybrid FPGA/DAQmx control to fully remote operation with live data streaming.

Workflows at a glance

# DAQmx location FPGA control Where Python runs
1 Dev machine (simulated cDAQ) → real cRIO None Dev machine, then cRIO
2 cRIO (via SSH) LabVIEW interactive VI cRIO (SSH)
3 cRIO (via SSH) Python nifpga (SSH) cRIO (SSH)
4 Remote machine → cRIO via gRPC Python nifpga (SSH) Split: FPGA on cRIO, DAQmx on dev machine

Project layout

Python Demo Slides.pdf                          # Presentation slides
HostCode/                                       # Code that runs on the dev machine
  ni9220acquisition.py                          # Workflow 1 – DAQmx demo (dev machine with simulated cDAQ)
  analog-input.py                               # Workflow 4 – gRPC DAQmx client
  gRPCClient/
    analog-input.py                             # Workflow 4 – gRPC client (co-located with stubs)
    stubs/                                      # Generated gRPC/protobuf stubs (nidaqmx, nidevice, etc.)
cRIOCode/                                       # Deploy all files here to /home/admin/cRIOCode/ on cRIO
  ni9220acquisition.py                          # Workflow 1 – cRIO variant (physical channel default)
  ai.py                                         # Workflow 2/3 – cRIO-local DAQmx with termchart plotting
  fpga_interface_sine-pwm.py                    # Workflow 3 – interactive nifpga CLI (sine-pwm.lvbitx)
  sine-pwm.lvbitx                               # FPGA bitfile for Workflow 3
  termchart.py                                  # Terminal plotting utility (bundled, used by ai.py)
  grpc-device-server                            # NI gRPC Device Server binary (Workflow 4)
LabVIEW FPGA Project/                           # LabVIEW project and associated Python scripts
  fpga_interface.py                             # Workflow 2 – FPGA offset-control CLI (criosineshift bitfile)
  fpga_interface_pwm-sine.py                    # Workflow 3 – alternate nifpga CLI with input validation
  cRIO Sine Shift.lvproj                        # LabVIEW project for the sine-shift FPGA VI
  FPGA Bitfiles/                                # Compiled .lvbitx bitfiles for LabVIEW project VIs

cRIO setup

Install Python on the cRIO (one time):

ssh admin@<crio-hostname>
sudo opkg install python3

Deploy the cRIO code:

scp -r cRIOCode/ admin@<crio-hostname>:/home/admin/

That's all that's needed to run Workflows 1–3 on the cRIO. Workflow 4 additionally requires the grpc-device-server binary, which is included in cRIOCode/.


Workflow 1: Simulated cDAQ → real cRIO DAQmx acquisition

Goal: Write and validate DAQmx acquisition code on a dev machine using a simulated cDAQ chassis, then deploy the same script unchanged to a cRIO with real C-Series hardware.

Dev machine (simulated hardware)

  1. Open NI MAX and create a simulated cDAQ chassis (e.g. NIcDAQ-9177) with an NI 9220 module in Slot 1.
  2. Run ni9220acquisition.py from the HostCode directory. The default channel NIcDAQ-9177/Mod1/ai0 matches the simulated chassis.
python HostCode/ni9220acquisition.py

The script runs a continuous analog input task at 10 kS/s, prints block-level min/max/avg and effective throughput, and stops on q + Enter or Ctrl+C.

Run on cRIO (real hardware)

ssh admin@<crio-hostname>
python /home/admin/cRIOCode/ni9220acquisition.py

Adjust physical_channel in the script if your NI 9220 is in a different slot. Its default channel is Mod1/ai0, matching a real cRIO slot layout.

A terminal-plotting variant (ai.py) is also available on the cRIO for visual output:

python /home/admin/cRIOCode/ai.py

Workflow 2: LabVIEW interactive FPGA VI + Python DAQmx on cRIO (SSH)

Goal: Run an FPGA VI interactively from LabVIEW while a Python DAQmx task running on the cRIO acquires data. Python is invoked remotely from a dev machine over SSH.

Setup

  1. Open LabVIEW FPGA Project/cRIO Sine Shift.lvproj in LabVIEW.
  2. Deploy and run the FPGA VI interactively on the cRIO target (LabVIEW handles the bitfile download and FPGA session).
  3. In a separate terminal on your dev machine, SSH into the cRIO and run the Python DAQmx acquisition script:
ssh admin@<crio-hostname>
python /home/admin/cRIOCode/ai.py

FPGA offset control (optional)

While LabVIEW holds the FPGA session, you can still adjust FPGA output parameters from Python using fpga_interface.py — but only when LabVIEW is not holding an exclusive FPGA lock. The script accepts a sine-wave offset (0–4) or stop:

python "/home/admin/LabVIEW FPGA Project/fpga_interface.py"
# Enter: 0, 1, 2, 3, 4, or stop

This targets criosineshift_FPGATarget_NI9381AdvancedIO.lvbitx on RIO0.


Workflow 3: Python nifpga FPGA control + Python DAQmx on cRIO (SSH)

Goal: Control the FPGA entirely from Python using the nifpga driver on the cRIO, while simultaneously running a DAQmx acquisition task — all invoked remotely over SSH from a dev machine. No LabVIEW runtime is required.

Run FPGA control (SSH into cRIO)

ssh admin@<crio-hostname>
python /home/admin/cRIOCode/fpga_interface_sine-pwm.py

The interactive CLI loads sine-pwm.lvbitx on RIO0 and accepts the following commands:

Command Effect
sine Switch FPGA output to sine wave mode
pwm Switch FPGA output to PWM mode
scale X Set amplitude scale (0.0–5.0)
duty X Set PWM duty cycle (0.0–1.0)
stop Halt FPGA loop and close session

Run DAQmx acquisition simultaneously (second SSH session)

Open a second SSH connection to the cRIO and run:

python /home/admin/cRIOCode/ai.py

Both processes run concurrently on the cRIO. The FPGA generates the signal; DAQmx acquires it.


Workflow 4: Python nifpga on cRIO (SSH) + remote DAQmx via gRPC with live plot

Goal: Control the FPGA from Python on the cRIO over SSH, while DAQmx acquisition is driven entirely from a dev machine using the NI gRPC Device Server. Acquired data streams back to the dev machine and is displayed in a Matplotlib plot.

cRIO setup

  1. Start the NI gRPC Device Server on the cRIO:
ssh admin@<crio-hostname>
/home/admin/cRIOCode/grpc-device-server

The server listens on port 31763 by default.

  1. In a second SSH session, start FPGA control:
python /home/admin/cRIOCode/fpga_interface_sine-pwm.py

Dev machine: remote DAQmx acquisition with live plot

Install dependencies on the dev machine:

cd HostCode/gRPCClient/stubs
pip install poetry && poetry install
pip install matplotlib numpy

Run the gRPC client:

python HostCode/analog-input.py [server_ip] [server_port] [physical_channel]

# Example:
python HostCode/analog-input.py crio-9049 31763 Mod1/ai0

The client creates a finite analog input task on the cRIO (1000 samples at 1 kS/s), reads the data over gRPC, and displays it in a Matplotlib window — all without NI-DAQmx installed on the dev machine.


Requirements

Dev machine

  • Python 3.9–3.11 (<3.12 required by gRPC stubs package)
  • nidaqmx — NI-DAQmx Python API (Workflow 1 dev/simulation only)
  • grpcio >= 1.49.1, numpy, matplotlib — Workflow 4 gRPC client
  • NI MAX — for creating simulated cDAQ chassis (Workflow 1)
  • LabVIEW with FPGA module — for building/deploying .lvbitx bitfiles and running interactive VI (Workflow 2)

cRIO (Linux RT)

  • Python 3 (sudo opkg install python3)
  • NI cRIO runtime with NI-DAQmx and NI-FPGA support installed via NI Package Manager

Hardware channel reference

Script Where it runs Default channel How to adjust
HostCode/ni9220acquisition.py Dev machine NIcDAQ-9177/Mod1/ai0 physical_channel variable
cRIOCode/ni9220acquisition.py cRIO Mod1/ai0 physical_channel variable
cRIOCode/ai.py cRIO Mod1/ai0 add_ai_voltage_chan() call
HostCode/analog-input.py Dev machine Mod1/ai0 PHYSICAL_CHANNEL constant or CLI arg
FPGA scripts cRIO RIO0 fpgaTarget variable

Notes

  • FPGA bitfile paths are resolved relative to the script location using os.path, so they work regardless of where the files are deployed on the cRIO.
  • Workflows 2 and 3 are mutually exclusive per FPGA session: only one process can hold the FPGA open at a time. LabVIEW (Workflow 2) and nifpga (Workflow 3) cannot both control the FPGA simultaneously.
  • The Workflow 4 gRPC client uses a finite acquisition (1000 samples). Increase samps_per_chan and num_samps_per_chan in analog-input.py for longer captures.
  • Compiled bitfiles for the LabVIEW project are in LabVIEW FPGA Project/FPGA Bitfiles/. The sine-pwm demo uses sine-pwm.lvbitx in cRIOCode/.

About

NI cRIO Python development workflows: DAQmx simulation, LabVIEW FPGA, nifpga, and remote gRPC acquisition

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors