The Orocos Hardware IO Component

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation, with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of this license can be found at http://www.fsf.org/copyleft/fdl.html.

Abstract

This document explains the interface of the hardware IO component.


Table of Contents

1. Introduction
2. Hardware Abstraction
2.1. Creating an IO Component
2.2. Sensing : Sensor Hardware Abstraction
2.3. Steering : Effector Hardware Abstraction

1. Introduction

This component depends on the interfaces defined in the Orocos Device Interface. See the Comedi component for implemenations of this interface.

2. Hardware Abstraction

This section explains how hardware sensors and outputs are abstracted using these Components in Orocos. They allow to do a quick test of existing device drivers, accessing them from a Component. They are not aimed to a specific application and the signals are propagated in data channels or through an object-per-sensor way.

2.1. Creating an IO Component

The OCL::IOComponent is created like all the other components in the Orocos framework :

  IOComponent   io("IOComponent");
	

You can choose another name freely. Additionally, you'll need to assign an activity such that the IOComponent can read and write data to the device drivers:

  RTT::PeriodicActivity   io_act(ORO_SCHED_RT, RTT::OS::HighestPriority, 0.001);
  io_act.run( io.engine() );
	

See the Component Builder's manual for more information on running components.

[Important]Important

When all device drivers are added, use io.start() to start the component, or data will not be read or written to the device drivers.

2.2. Sensing : Sensor Hardware Abstraction

The IO Component knows two fundamental types of sensors : Analog Inputs and Digital Inputs. Multichannel Analog and Digital input cards are defined in the Orocos Device Interface.

The component provides methods to add Analog and Digital Inputs.

2.2.1. Adding an Analog Input Interface card

You can add all channels of an Analog interface card using:

  AnalogInInterface* analog_input_card = ...
  io.addAnalogInInterface("AInCard", analog_input_card );
	  

The analog_input_card object must implement the RTT::AnalogInInterface. If there is already a card named "AInCard", addAnalogInput returns false. A DataPort is created with the same name which contains all channels of analog_input_card.

Likewise, you can remove it again using:

  io.removeAnalogInInterface("AInCard");
	  

2.2.2. Adding and Removing an Analog Input

An unlimited number of Analog Inputs can be added to the IOComponent :

  int A_CHANNEL_1 = 1;
  io.addAnalogInput("AIn_1", analog_input_card, A_CHANNEL_1 );
	  

This methods creates a DataPort<double> object with the name "AIn_1" from which other components may read. It's value is updated from an analog_input_card on channel A_CHANNEL_1. The analog_input_card must implement the RTT::AnalogInInterface. If there is already an "AIn_1" DataObject, addAnalogInput returns false.

The RTT::AnalogInput can also be read from an Orocos Program Script or State Description :

  var double result = IOComponent.AIn_1.Get()
  var int    raw_result = IOComponent.AIn_1_raw.Get()
	  

It can be removed with the following method call :

  io.removeAnalogInput("AIn_1");
	  

Which removes the "AIn_1" Port from the interface.

2.2.3. Using Virtual Channels

Analog inputs can be ordered in a virtual channels DataPort. This allows a more generic way of reading inputs from other components. The Channel Port which is created is of the type RTT::DataPort< std::vector<double> > and has the name "InputValues". AnalogInputs can be added to a channel in this vector :

  int A_VIRT_CHAN = 1;
  int A_CHANNEL   = 5;
  io.addChannel(A_VIRT_CHAN, analog_input_card, A_CHANNEL );
	  

Which demonstrates that channel 5 of the RTT::AnalogInInterface is inserted in position 1 of the Channel DataObject. If this channel was already taken, addChannel returns false;

Removing a virtual channel is quite straightforward :

  io.removeChannel( A_VIRT_CHAN );
	  

2.2.4. Adding an Digital Input Interface card

You can add all channels of an Digital interface card using:

  DigitalInInterface* digital_input_card = ...
  io.addDigitalInInterface("DInCard", digital_input_card );
	  

The digital_input_card object must implement the RTT::DigitalInInterface. If there is already a card named "DInCard", addDigitalInput returns false. The bits of the card are accessible as shown below. The names to use are "DInCardX" with X the channel number from zero to the number of channels.

2.2.5. Adding Digital Inputs

Digital Inputs are available through the method interface.

A RTT::DigitalInput is added as such :

  int D_CHANNEL = 2;
  io.addDigitalInput("DIn_1", digital_input_card, D_CHANNEL );
	  

Which is very similar to adding an Analog Input. The IOComponent exposes this Input through the methods :

  bool result = io.isOn("DIn_1");
	  

Or in a program or state script :

  var bool result = IOComponent.isOn("DIn_1")
	  

2.3. Steering : Effector Hardware Abstraction

The OCL::IOComponent support sending signals to hardware as well.

2.3.1. Adding an Analog Output Interface card

You can add all channels of an Analog Output interface card using:

  AnalogOutInterface* analog_output_card = ...
  io.addAnalogOutInterface("AOutCard", analog_output_card );
	  

The analog_output_card object must implement the RTT::AnalogOutInterface. If there is already a card named "AOutCard", addAnalogOutput returns false. A DataPort is created with the same name which contains all channels of analog_output_card.

2.3.2. Adding and Removing Analog Outputs

Analogous to Analog inputs :

  int A_CHANNEL_1 = 1;
  io.addAnalogOutput("AOut_1", analog_output_card, A_CHANNEL_1 );
	  

This methods creates a DataPort<double> object with the name "AOut_1". The analog_output_card must implement the RTT::AnalogOutInterface. If there is already an "AOut_1" DataPort, addAnalogOutput returns false.

The RTT::AnalogOutput can then be read from an Orocos Program Script or State Machine :

  var double result = IOComponent.AOut_1.Get()
  var int    raw_result = IOComponent.AOut_1_raw.Get()
	  

An AnalogOutput can be removed with the following method call :

  io.removeAnalogOutput("AOut_1");
	  

This removes the AOut_1 DataPort as well.

2.3.3. Using Virtual Channels

Analog Outputs can be read from a virtual channels DataPort. The IOComponent creates a DataPort< std::vector<double> > with the name "OutputValues" to which other components can connect their WriteDataPorts. Analog Outputs can be read from this vector :

  int A_VIRT_CHAN = 1;
  int A_CHANNEL   = 5;
  io.addChannel(A_VIRT_CHAN, analog_output_card, A_CHANNEL );
	  

Which demonstrates that channel 5 of the RTT::AnalogOutInterface is set to the value of virtual channel 1. If this virtual channel was already taken, addChannel returns false;

Removing a virtual channel is again quite straightforward :

  io.removeChannel( A_VIRT_CHAN );
	  

2.3.4. Adding an Digital Output Interface card

You can add all channels of an Digital interface card using:

  DigitalOutInterface* digital_output_card = ...
  io.addDigitalOutInterface("DOutCard", digital_output_card );
	  

The digital_output_card object must implement the RTT::DigitalOutInterface. If there is already a card named "DOutCard", addDigitalOutput returns false. The bits of the card are accessible as shown below. The names to use are "DOutCardX" with X the channel number from zero to the number of channels.

2.3.5. Adding Digital Outputs

Digital Outputs are not read from Ports, as digital signals are set by methods.

A Digital Output is added as such :

  int D_CHANNEL = 2;
  io.addDigitalOutput("DOut_1", digital_output_card, D_CHANNEL );
	  

Which is again analogous to adding digital inputs. The IOComponent exposes this Output through the methods :

  io.switchOn("DOut_1");
  bool result = io.isOn("DOut_1");
  io.switchOff("DOut_1");
	  

Or in a program or state script :

  do IOComponent.switchOn("DOut_1")
  var bool result = IOComponent.isOn("DOut_1")
  do IOComponent.switchOff("DOut_1")