Tool inputs and outputs

The tool connector on the flange carries six inputs and outputs. The IOs of the tool are prefixed with t, and the robot user manual documents their wiring on the connector: pin assignment, wire colors, ground and supply. The controller carries twenty more, see Controller inputs and outputs.

Mapping

The labels of this API and the board signals of the robot documentation name the same six signals:

Tool IO mapping

Label

Board signal

tdi1

TI0

tdi2

TI1

tdo1

TO0

tdo2

TO1

tai1

AI1

tai2

AI2

A digital label does not repeat the number of its board signal: tdi1 is TI0 and tdo1 is TO0. The analog labels do, tai1 is AI1. The connector exposes no analog output.

Reading and writing

get_all() returns every input and output at once, keyed by label:

1 from pyniryo_nate import Nate
2 from pyniryo_nate.models import IOLabel
3
4 nate = Nate(hostname="10.10.10.10", login=("user", "secret"))
5
6 states = nate.io.get_all()
7 print(states.digital_inputs[IOLabel.TDI1].value)
8
9 nate.io.set_digital_output(IOLabel.TDO1, True)

on_digital_io() and on_analog_io() report a single IO as it changes, without polling:

1 unsubscribe = nate.io.on_digital_io(IOLabel.TDI1, lambda io: print(io.value))
2
3 # later, to stop receiving the changes
4 unsubscribe()

Controlling a gripper

This section covers a gripper whose tool IOs are configured for digital IO control, where the gripper is driven through the digital outputs tdo1 and tdo2. The tool IOs can also be configured for RS485 control, where the gripper is driven over serial through the analog IOs instead; that mode is out of the scope of this document.

There is no dedicated method for a gripper in this API: it is controlled with the same update_states() used for any digital output. Prefer sending tdo1 and tdo2 together in a single grouped call over two separate set_digital_output() calls: written one after the other, the outputs pass through an intermediate combined state that may not correspond to any behavior the gripper was configured for.

 1 from pyniryo_nate import Nate
 2 from pyniryo_nate.models import DigitalIO, IOLabel
 3
 4 nate = Nate(hostname="10.10.10.10", login=("user", "secret"))
 5
 6 # The states to write for a given behavior depend on how the gripper is configured.
 7 nate.io.update_states([
 8     DigitalIO(id=IOLabel.TDO1, value=False),
 9     DigitalIO(id=IOLabel.TDO2, value=False),
10 ])

Danger

A gripper’s behavior for a given pair of tdo1/tdo2 states is configured by the user, on the gripper or in its configuration. Nothing guarantees that, say, tdo1=False, tdo2=False opens the gripper and tdo1=True, tdo2=True closes it: another gripper, or the same one reconfigured, can wire these states to the opposite behavior, or to something else entirely. This is why this API exposes no open_gripper or close_gripper function: it has no way to know a mapping that is user configurable. Check how your gripper is configured before writing to its outputs.

Analog inputs without a measurement

An analog input does not always measure. An input that is connected to no measurement chain reports nothing to read, and a reading is then unavailable rather than zero. AnalogIO carries that case explicitly: value is None, and unavailable_reason says why.

 1 from pyniryo_nate import Nate
 2 from pyniryo_nate.models import AnalogUnavailableReason, IOLabel
 3
 4 nate = Nate(hostname="10.10.10.10", login=("user", "secret"))
 5
 6 tai1 = nate.io.get_all().analog_inputs[IOLabel.TAI1]
 7
 8 if tai1.is_available:
 9     print(f"tai1 measures {tai1.value} V")
10 elif tai1.unavailable_reason == AnalogUnavailableReason.HIGH_Z:
11     print("tai1 is in high impedance, it is connected to no measurement chain")
12 else:
13     print(f"tai1 has no measurement: {tai1.unavailable_reason}")

The two reasons are:

Reasons for an unavailable measurement

Reason

Meaning

AnalogUnavailableReason.HIGH_Z

The input sits in high impedance, connected to no measurement chain. This is the mode an input holds until it is configured for voltage or current.

AnalogUnavailableReason.RS485

The input is driven as an RS485 line. Analog acquisition and serial communication are mutually exclusive on it.

Note

tai1 and tai2 share their lines with the RS485 bus of the tool board, which is what the second reason refers to. RS485 control of the tool IOs is not available on this generation; both inputs read a voltage.

Danger

Never fall back to a default value when value is None. 0.0 is a legitimate measurement, so a program that reads io.value or 0.0 cannot tell a grounded sensor from an unwired one. Test is_available, or value is None, before using the value.

The same holds for the values pushed to on_analog_io(): the callback receives an AnalogIO whose value may be None.

An AnalogIO that was read is not meant to be written back as it is. update_states() raises ValueError on an analog output whose value is None, rather than writing a zero to the board.