Read & write I/O signals
Read and write digital, analog and group I/O signals of an ABB controller, pulse a signal and simulate one during tests.
Reading an I/O signal of an ABB controller is robot.Rws.Io.GetSignal(network, device, signal), and writing one is robot.Rws.Io.SetSignalValue(network, device, signal, value). Digital, analog and group signals all go through the same two methods, only the value changes. I/O needs no mastership, it needs a user account with the write grant.
How a signal is identified
A signal has three parts: the network it belongs to, the device it is connected to, and its name. Local is the internal network of the controller, and the signals of the robot itself are usually on it.
IoSignalItem.Path gives the three parts joined, for example Local/Board10/DO_Gripper. If you only know the name of a signal, find its network and its device with GetSignals() or with a search.
Read a signal
AbbController robot = new AbbController();robot.Connect("192.168.0.1");// A signal is identified by its network, its device and its nameIoSignalItem signal = robot.Rws.Io.GetSignal("Local", "Board10", "DO_Gripper");Console.WriteLine(signal.Path); // Local/Board10/DO_GripperConsole.WriteLine(signal.Type); // DigitalOutputConsole.WriteLine(signal.LogicalValue); // 1Console.WriteLine(signal.LogicalState); // NotSimulatedConsole.WriteLine(signal.PhysicalValue); // 1Console.WriteLine(signal.PhysicalState); // Valid// Every signal of the controller, in one callIoSignalItem[] signals = robot.Rws.Io.GetSignals();foreach (IoSignalItem item in signals){Console.WriteLine($"{item.Path} = {item.LogicalValue} ({item.Type})");}robot.Disconnect();}
A signal has two values. LogicalValue is what the program and the network see. PhysicalValue is what the device really carries. They differ when the signal is simulated, or inverted in the configuration. LogicalState says whether the signal is simulated, PhysicalState whether the value can be trusted.
GetSignals() returns every signal of the controller in one request. It is the fast way to build a table, but it carries only the name, the type, the category, the logical value and the logical state. Call GetSignal on one signal to get everything.
Digital, analog and group
IoSignalType | Value | Written with |
|---|---|---|
DigitalInput, DigitalOutput | 0 or 1 | SetSignalValue(..., 1) |
AnalogInput, AnalogOutput | any value inside the configured range | SetSignalValue(..., 12.5f) |
GroupInput, GroupOutput | the integer made of the bits of the group | SetSignalValue(..., 5) |
LogicalValue is a float?, and SetSignalValue takes a float. A group of 4 bits written with the value 5 sets the bits 1 and 3. IoSignalConfiguration.SignalBits gives the width of a group.
Write a signal
Only an output can be written, unless the input is simulated. Writing a read only signal fails with an RwsException.
AbbController robot = new AbbController();robot.Connect("192.168.0.1");// A digital signal takes 0 or 1robot.Rws.Io.SetSignalValue("Local", "Board10", "DO_Gripper", 1);// An analog or a group signal takes any value inside its rangerobot.Rws.Io.SetSignalValue("Local", "Board10", "AO_Speed", 12.5f);// The last argument writes the change in the event log of the controllerrobot.Rws.Io.SetSignalValue("Local", "Board10", "DO_Gripper", 0, true);// The controller applies the value 500 ms later, and answers immediatelyrobot.Rws.Io.SetSignalValueDelayed("Local", "Board10", "DO_Gripper", 1, 500);robot.Disconnect();}
Pulse, toggle and invert
A pulse is done by the controller, which is more precise than two writes separated by a Thread.Sleep in your application.
AbbController robot = new AbbController();robot.Connect("192.168.0.1");// Three pulses to 1, 200 ms active and 200 ms passiverobot.Rws.Io.PulseSignal("Local", "Board10", "DO_Gripper", 1, 3, 200, 200);// Same, with the pulse lengths configured on the controllerrobot.Rws.Io.PulseSignal("Local", "Board10", "DO_Gripper", 1, 1);// Toggle pulses the signal by starting from the opposite of its current valuerobot.Rws.Io.ToggleSignal("Local", "Board10", "DO_Gripper", 1, 2, 200, 200);// Invert writes the opposite of the current value, oncerobot.Rws.Io.InvertSignal("Local", "Board10", "DO_Gripper", 1);robot.Disconnect();}
Wait for a signal
There is no subscription in this SDK, a value is read by asking for it. To wait for an input, poll it with a period and a timeout. 200 ms is a reasonable period, a shorter one loads the controller for nothing.
AbbController robot = new AbbController();robot.Connect("192.168.0.1");// Ask the robot to work, then wait for its answerrobot.Rws.Io.SetSignalValue("Local", "Board10", "DO_Start", 1);if (!WaitValue(robot, "Local", "Board10", "DI_Done", 1, 10000))throw new Exception("The robot did not answer in 10 seconds");robot.Rws.Io.SetSignalValue("Local", "Board10", "DO_Start", 0);// Polls one signal until it reaches the expected value, or the timeout expires.// 200 ms is a reasonable period : a shorter one loads the controller for nothing.static bool WaitValue(AbbController robot, string network, string device, string signal,float expected, int timeoutMs){DateTime limit = DateTime.UtcNow.AddMilliseconds(timeoutMs);while (DateTime.UtcNow < limit){IoSignalItem item = robot.Rws.Io.GetSignal(network, device, signal);if (item.LogicalValue == expected)return true;Thread.Sleep(200);}return false;}}
When the reaction has to be faster than that, do the waiting in RAPID with a WaitDI, and use the SDK to give the program the order to start.
Simulate a signal during a test
A simulated signal keeps the value written by the client and stops following its device. This is how an input is forced from a test bench, on a real controller as well as on a virtual one.
AbbController robot = new AbbController();robot.Connect("192.168.0.1");// Simulate an input: it keeps the value written by the clientrobot.Rws.Io.SetSignalState("Local", "Board10", "DI_PartPresent", true);robot.Rws.Io.SetSignalValue("Local", "Board10", "DI_PartPresent", 1);IoSignalItem signal = robot.Rws.Io.GetSignal("Local", "Board10", "DI_PartPresent");Console.WriteLine(signal.LogicalState); // Simulated// Give the signal back to its devicerobot.Rws.Io.SetSignalState("Local", "Board10", "DI_PartPresent", false);// Or stop simulating every simulated signal of the controller at oncerobot.Rws.Io.UnblockSignals();robot.Disconnect();}
Do not leave a signal simulated at the end of a test. UnblockSignals() stops the simulation of every simulated signal of the controller at once.
Who is allowed to write a signal
A signal can be write protected depending on who writes it and in which operation mode. When a write is refused and the mastership is not the reason, read the configuration of the signal.
AbbController robot = new AbbController();robot.Connect("192.168.0.1");IoSignalConfiguration config = robot.Rws.Io.GetSignalConfiguration("Local", "Board10", "DO_Gripper");Console.WriteLine(config.SignalName); // DO_GripperConsole.WriteLine(config.SignalBits); // 1// Who is allowed to write the signal, and in which operation modeConsole.WriteLine(config.Rapid); // a RAPID programConsole.WriteLine(config.LocalManual); // the teach pendant, in manual modeConsole.WriteLine(config.LocalAuto); // the teach pendant, in auto modeConsole.WriteLine(config.RemoteManual); // a remote client, in manual modeConsole.WriteLine(config.RemoteAuto); // a remote client, in auto moderobot.Disconnect();}
Find the signals you need
SearchSignals filters on the name, the device, the network, the type and the category. A second criteria can be inverted to exclude what it matches, which is how the safety signals are left out of a list.
AbbController robot = new AbbController();robot.Connect("192.168.0.1");// Every digital output of one deviceIoSignalSearchCriteria criteria = new IoSignalSearchCriteria();criteria.DeviceName = "Board10";criteria.Type = IoSignalType.DigitalOutput;IoSignalItem[] outputs = robot.Rws.Io.SearchSignals(criteria);foreach (IoSignalItem signal in outputs){Console.WriteLine($"{signal.Name} = {signal.LogicalValue}");}// The extended search also reports the physical value and the write access levelIoSignalItem[] extended = robot.Rws.Io.SearchSignalsExtended(criteria, null, 0, 50);Console.WriteLine(extended[0].PhysicalValue);Console.WriteLine(extended[0].Quality);Console.WriteLine(extended[0].WriteAccessLevel);// A second inverted criteria excludes what it matches, here the safety signalsIoSignalSearchCriteria exclude = new IoSignalSearchCriteria();exclude.Category = "safety";exclude.Invert = true;IoSignalItem[] withoutSafety = robot.Rws.Io.SearchSignals(criteria, exclude);robot.Disconnect();}
Going further
- I/O signals, devices & networks, the complete reference
- Start & stop a RAPID program, to trigger a program that reacts to your signals
- Read & write RAPID variables, the other way of exchanging data with a program
// Gets a single I/O signal, including its physical value and time stamps (synchronous)IoSignalItem GetSignal(string network, string device, string signal);// Gets the runtime configuration properties of an I/O signal (synchronous)IoSignalConfiguration GetSignalConfiguration(string network, string device, string signal);// Gets every I/O signal defined in the controller (synchronous) A controller usually exposes several hundreds of signals. Use Nullable%7bSystem.Int32%7d) to narrow the result down to a network, a device, a category or a signal type.IoSignalItem[] GetSignals();// Inverts the value of an I/O signal (synchronous) Only digital and group signals can be inverted.void InvertSignal(string network, string device, string signal, float value, bool logToEventLog = false);// Pulses the value of an I/O signal (synchronous) Only digital and group signals can be pulsed.void PulseSignal(string network, string device, string signal, float value, int pulses, int? activePulseLength = null, int? passivePulseLength = null, bool logToEventLog = false);// Searches the I/O signals matching the given criteria (synchronous) The returned signals carry their name, type, category, logical value and logical state. Use Nullable%7bSystem.Int32%7d) to also get their physical value, time stamps and write access level.IoSignalItem[] SearchSignals(IoSignalSearchCriteria criteria = null, IoSignalSearchCriteria secondCriteria = null, int? start = null, int? limit = null);// Searches the I/O signals matching the given criteria and returns their extended properties (synchronous) In addition to Nullable%7bSystem.Int32%7d), the returned signals carry their physical value, quality, time stamps and write access level.IoSignalItem[] SearchSignalsExtended(IoSignalSearchCriteria criteria = null, IoSignalSearchCriteria secondCriteria = null, int? start = null, int? limit = null);// Simulates or stops simulating an I/O signal (synchronous) A simulated signal keeps the logical value written by the client and no longer follows its physical value.void SetSignalState(string network, string device, string signal, bool simulated);// Writes the value of an I/O signal (synchronous)void SetSignalValue(string network, string device, string signal, float value, bool logToEventLog = false);// Writes the value of an I/O signal in "queued delayed" mode (synchronous) The controller queues the write and applies it once the delay has elapsed.void SetSignalValueDelayed(string network, string device, string signal, float value, int delay, bool logToEventLog = false);// Pulses an I/O signal by toggling its current value (synchronous) Only digital and group signals can be toggled.void ToggleSignal(string network, string device, string signal, float value, int pulses, int? activePulseLength = null, int? passivePulseLength = null, bool logToEventLog = false);// Removes the simulation of every simulated I/O signal of the controller (synchronous)void UnblockSignals();
Every method also exists in an asynchronous version, with the same name followed by Async and an optional CancellationToken.
I/O signal defined in the robot controller. Returned by IoService.GetSignals(), IoService.GetSignal(), IoService.SearchSignals() and IoService.SearchSignalsExtended(). Depending on the method used, only a subset of the properties is filled in: the signal lists carry the name, type, category, logical value and logical state only.
| Member | Type | Description |
|---|---|---|
IoSignalItem() Constructor | Initializes a new instance of the IoSignalItem class | |
Category Property | string | Category the signal belongs to, for example "safety" |
DeviceName Property | string | Name of the device the signal is connected to, for example "DRV_1" |
LogicalState Property | IoSignalLogicalState | Logical state of the signal (simulated or not) |
LogicalTimeMicroseconds Property | long? | Microseconds part of the global time at which the logical value was updated, null when not reported |
LogicalTimeSeconds Property | long? | Seconds part of the global time at which the logical value was updated, null when not reported |
LogicalValue Property | float? | Logical value of the signal, null when the controller did not report it |
Name Property | string | Name of the signal, for example "DRV1BRAKE" |
NetworkName Property | string | Name of the network the signal belongs to, for example "Local" |
Path Property | string | Full path of the signal, "{network}/{device}/{signal}" (for example "Local/DRV_1/DRV1BRAKE") |
PhysicalState Property | IoSignalPhysicalState | Physical state of the signal. Only reported when reading a single signal with IoService.GetSignal(). |
PhysicalTimeMicroseconds Property | long? | Microseconds part of the global time at which the physical value was updated, null when not reported |
PhysicalTimeSeconds Property | long? | Seconds part of the global time at which the physical value was updated, null when not reported |
PhysicalValue Property | float? | Physical value of the signal, null when the controller did not report it. Only reported by IoService.GetSignal() and IoService.SearchSignalsExtended(). |
Quality Property | string | Quality of the signal, reported as a numeric code by IoService.GetSignal() and as a textual value (for example "good") by IoService.SearchSignalsExtended() |
Type Property | IoSignalType | Type of the signal |
WriteAccessLevel Property | string | Access level required to write the signal, for example "None". Only reported by IoService.SearchSignalsExtended(). |
ToString() Method | string | Returns a string representation of this signal |
Type of an I/O signal
| Name | Value | Description |
|---|---|---|
AnalogInput | 4 | Analog input |
AnalogOutput | 3 | Analog output |
DigitalInput | 2 | Digital input |
DigitalOutput | 1 | Digital output |
GroupInput | 5 | Group input |
GroupOutput | 6 | Group output |
Unknown | 0 | The signal type could not be determined |
Runtime configuration properties of an I/O signal. Returned by IoService.GetSignalConfiguration().
| Member | Type | Description |
|---|---|---|
IoSignalConfiguration() Constructor | Initializes a new instance of the IoSignalConfiguration class | |
LocalAuto Property | bool? | Whether a local client can write the signal in auto mode |
LocalManual Property | bool? | Whether a local client can write the signal in manual mode |
Rapid Property | bool? | Whether a RAPID client can write the signal in both manual and auto mode |
RemoteAuto Property | bool? | Whether a remote client can write the signal in auto mode |
RemoteManual Property | bool? | Whether a remote client can write the signal in manual mode |
SetByDeviceTransfer Property | bool? | Whether the bits of this signal are set by a device transfer operation. Not reported by every controller, null when absent from the response. |
SignalBits Property | int? | Number of bits of the signal, null when not reported |
SignalName Property | string | Name of the signal, for example "DRV1CHAIN2" |
ToString() Method | string | Returns a string representation of this signal configuration |
Criteria used to search I/O signals with IoService.SearchSignals() and IoService.SearchSignalsExtended(). Every property is optional: the properties left to null are not sent to the controller, and an empty criteria matches every signal. Two criteria can be combined by passing a second instance to the search methods, in which case a signal is returned only when it matches both. One of the two criteria should then have Invert set to true, otherwise the result is the same as with a single criteria.
| Member | Type | Description |
|---|---|---|
IoSignalSearchCriteria() Constructor | Initializes a new instance of the IoSignalSearchCriteria class | |
Blocked Property | bool? | Whether only the blocked (simulated) signals are searched |
Category Property | string | Category of the searched signals, for example "safety" |
CategoryPrefix Property | string | Category prefix of the searched signals |
DeviceName Property | string | Name of the device the searched signals are connected to |
Invert Property | bool? | Whether the criteria is inverted: the signals matching it are excluded from the result |
Name Property | string | Name of the searched signals |
NetworkName Property | string | Name of the network the searched signals belong to |
Type Property | IoSignalType? | Type of the searched signals, null to search every type |
ToString() Method | string | Returns a string representation of this search criteria |