NI Analog Write Task
Learn how to send analog commands to NI devices with Synnax.
For task lifecycle management, see the Task Basics page.
How Commands Work
Write tasks use command and state channels:
- Command channels (
_cmd): Write values here to set analog outputs - State channels (
_state): Reflect the current output state - Command time channels (
_cmd_time): Index channels storing command timestamps
When you write to a command channel, the task processes it and updates the state channel, providing acknowledgment that the command was executed.
Task Configuration Reference
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | - | Human-readable task name |
state_rate | number | No | 20 | Rate (Hz) at which state channels are updated |
data_saving | boolean | No | false | Enable permanent storage in Synnax |
auto_start | boolean | No | false | Automatically start task after configuration |
channels | array | Yes | - | List of analog output channel configurations |
Channel Types Reference
Voltage (ao_voltage)
ao_voltage)| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
cmd_channel | number | Yes | - | Synnax command channel key |
state_channel | number | Yes | - | Synnax state channel key |
device | string | Yes | - | Device identifier |
port | number | Yes | - | Physical port |
min_val | number | No | -10.0 | Minimum voltage (Volts) |
max_val | number | No | 10.0 | Maximum voltage (Volts) |
custom_scale | object | No | - | Custom scaling |
Current (ao_current)
ao_current)| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
cmd_channel | number | Yes | - | Synnax command channel key |
state_channel | number | Yes | - | Synnax state channel key |
device | string | Yes | - | Device identifier |
port | number | Yes | - | Physical port |
min_val | number | No | 0.004 | Minimum current (Amps) |
max_val | number | No | 0.02 | Maximum current (Amps) |
custom_scale | object | No | - | Custom scaling |
Important Rules
- Command/State pairs: Each analog output requires both a command and state channel.
- One task per module: Only one running task can claim a module at a time.
- State rate: Higher state rates provide faster feedback but consume more resources.
How-To
Configure and run task
import synnax as sy
from synnax.hardware import ni
client = sy.Synnax()
# Retrieve device
c_dev = client.hardware.devices.retrieve(name="Mod1_Current")
# Create command and state time indices
ao_cmd_time = client.channels.create(
name="ao_cmd_time",
is_index=True,
data_type=sy.DataType.TIMESTAMP,
retrieve_if_name_exists=True,
)
ao_state_time = client.channels.create(
name="ao_state_time",
is_index=True,
data_type=sy.DataType.TIMESTAMP,
retrieve_if_name_exists=True,
)
# Create command and state channels
current_cmd = client.channels.create(
name="current_cmd",
index=ao_cmd_time.key,
data_type=sy.DataType.FLOAT32,
retrieve_if_name_exists=True,
)
current_state = client.channels.create(
name="current_state",
index=ao_state_time.key,
data_type=sy.DataType.FLOAT32,
retrieve_if_name_exists=True,
)
# Create and configure task
task = ni.AnalogWriteTask(
name="Analog Write Task",
state_rate=sy.Rate.HZ * 20,
data_saving=True,
channels=[
ni.AOCurrentChan(
cmd_channel=current_cmd.key,
state_channel=current_state.key,
device=c_dev.key,
port=0,
min_val=0.004,
max_val=0.02,
),
],
)
client.hardware.tasks.configure(task)
# Start task and write commands
with task.run():
with client.open_writer(
start=sy.TimeStamp.now(),
channels=["current_cmd"],
) as writer:
# Set output to 0.01A
writer.write({
"current_cmd": 0.01,
})
# Read back state
with client.open_streamer(["current_state"]) as streamer:
frame = streamer.read()
print(f"State: {frame['current_state']}") Edit task configuration
# Retrieve existing task
task = client.hardware.tasks.retrieve(name="Analog Write Task")
task = ni.AnalogWriteTask(internal=task)
# Update task-level configuration
task.config.auto_start = True
task.config.state_rate = int(sy.Rate.HZ * 50)
# Update channel-level configuration
task.config.channels[0].port = 1
task.config.channels[0].min_val = 0.002
task.config.channels[0].max_val = 0.01
# Apply changes
client.hardware.tasks.configure(task) Configure and run task
import { Synnax, TimeStamp, Rate } from "@synnaxlabs/client";
const client = new Synnax();
// Retrieve device
const cDev = await client.hardware.devices.retrieve({ name: "Mod1_Current" });
// Create command and state time indices
const aoCmdTime = await client.channels.create({
name: "ao_cmd_time",
isIndex: true,
dataType: "timestamp",
retrieveIfNameExists: true,
});
const aoStateTime = await client.channels.create({
name: "ao_state_time",
isIndex: true,
dataType: "timestamp",
retrieveIfNameExists: true,
});
// Create command and state channels
const currentCmd = await client.channels.create({
name: "current_cmd",
index: aoCmdTime.key,
dataType: "float32",
retrieveIfNameExists: true,
});
const currentState = await client.channels.create({
name: "current_state",
index: aoStateTime.key,
dataType: "float32",
retrieveIfNameExists: true,
});
// Create and configure task
const task = await client.hardware.tasks.create({
name: "Analog Write Task",
type: "ni_analog_write",
config: JSON.stringify({
state_rate: 20,
data_saving: true,
channels: [
{
type: "ao_current",
cmd_channel: currentCmd.key,
state_channel: currentState.key,
device: cDev.key,
port: 0,
min_val: 0.004,
max_val: 0.02,
},
],
}),
});
// Start task
await task.executeCommandSync("start");
// Write command
const writer = await client.openWriter({
start: TimeStamp.now(),
channels: ["current_cmd"],
});
await writer.write({
current_cmd: 0.01,
});
// Read state
const streamer = await client.openStreamer(["current_state"]);
const frame = await streamer.read();
console.log(`State: ${frame["current_state"]}`);
// Stop task
await task.executeCommandSync("stop");
await writer.close();
await streamer.close(); Edit task configuration
// Retrieve existing task
const task = await client.hardware.tasks.retrieve({ name: "Analog Write Task" });
// Parse and update configuration
const config = JSON.parse(task.config);
// Update task-level configuration
config.auto_start = true;
config.state_rate = 50;
// Update channel-level configuration
config.channels[0].port = 1;
config.channels[0].min_val = 0.002;
config.channels[0].max_val = 0.01;
// Apply changes
await client.hardware.tasks.create({
key: task.key,
name: task.name,
type: task.type,
config: JSON.stringify(config),
});