Data Port Communication (Push type)


Here, Sender RTC which has OutPort(s), and Receiver RTC which has InPort(s) are shown.

Setting of RTC Builder

If you use original data type, you must write IDL file and configure your RTC Builder.

Select menu -> window -> setting, and in the dialog, select “RTC Builder” -> “Data Type”, and select the folder your IDL file is placed in.

The default data type IDL is in C:¥Program Files (x86)¥OpenRTM-aist¥1.0¥rtm¥idl

Setting IDL Paths for RTC Builder

Setting IDL Paths for RTC Builder

I recommend you to reboot your eclipse.

ConsoleIn (RTC with OutPort)

ConsoleIn RTC receives your key inputs

RTC Builder

Tab Parameter Setting
Basic Module name ConsoleIn
Module description Console In Component
Module version 1.0.0
Module vender Your Name
Module category TEST
Component type STATIC
Component Kind Data Flow
Component’s activity type PERIODIC
Number of maximum instance 1
Execution Type Periodic Execution Context
Execution Rate 1.0
Abstract Not Important
RTC Type Not Important
Output Project ConsoleIn
Activity on_execute Check
Data Port
(OutPort Profile)
PortName out (Port name)
DataType TimedLong (Data type)
VarName out (variable which has data of the port)
Disp. Position RIGHT (Display position in RTSE)
Language & environment Language C++, Java, Python

Coding

You can find two variables “m_out” and “m_outOut”.
m_out is data buffer of OutPort, and m_outOut is OutPort itself. In the auto generated initialization code, both variables are connected so the data can automatically transported between two variables.

The writing sequence of OutPort is …
1. Write data to m_out (buffer).
2. Call m_outOut.write function.

 
RTC::ReturnCode_t ConsoleIn::onExecute(RTC::UniqueId ec_id)
{
  std::cout << "Input number:" << std::endl;
  std::cin >> m_out.data;
  m_outOut.write();
  return RTC::RTC_OK;
}

If out is sequence type (variable length array), you need to change the buffer length by calling “length” function.

RTC::ReturnCode_t ConsoleSeqIn::onExecute(RTC::UniqueId ec_id)
{
  m_out.data.length(3);
  for(int i = 0;i < 3;i++) {
    long value;
    std::cout << "Input number:" << std::ends;
    std::cin >> value;
    std::cout << "Data is " << value << std::endl;
    m_out.data[i] = value;
  }
  m_outOut.write();
  return RTC::RTC_OK;
}
In Java, you can find three variables.

  • m_out_val : TimedLong
  • m_out : DataRef
  • m_outOut : DataPort

You must watch two of them, m_out (DataRef type) and m_outOut (DataPort type).

    @Override
    protected ReturnCode_t onExecute(int ec_id) {
    	BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    	String line;
    	try {
    		System.out.println("Input Number");
    		line = reader.readLine();
    		System.out.println("Number is " + line);
    	} catch (IOException ioex) {
    		System.out.println("Excepiton occured in onExecute.");
    		return RTC.ReturnCode_t.RTC_ERROR;
    	}
 
    	m_out.v.data = Integer.parseInt(line);
    	m_out.v.tm = new RTC.Time(0, 0);
    	m_outOut.write();
 
        return super.onExecute(ec_id);
    }

You must write your data to m_out.v parameter. If you use Sequence type, data is array (collection type).
Difference to C++ is Timestamp. The timestamp is not automatically generated, so you must manually set the timestamp at least once.

If you use sequence type (variable length array), “m_out.v.data” is array.
First, allocate enough size of array for the “m_out.v.data”. (I recommend you to set the memory in onInitialized function, because “new” operator is heavy.)

    @Override
    protected ReturnCode_t onExecute(int ec_id) {
    	BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    	String lineBuffer;
	    m_out.v.tm = new RTC.Time(0, 0);    	
    	m_out.v.data = new int[3];
    	for(int i = 0;i < 3;i++) {
	    	System.out.print("Input Number:");
	    	try {
	    		lineBuffer = reader.readLine();
	    	} catch (IOException ioe) {
	    		System.out.println(ioe);
	    		return RTC.ReturnCode_t.RTC_ERROR;
	    	}
	    	int value = Integer.parseInt(lineBuffer);
	    	System.out.println("Value = " + value);
	    	m_out.v.data[i] = value;
    	}
    	m_outOut.write();
        return super.onExecute(ec_id);
    }
In Python, if you use OutPort named “out”, you can find “_d_out” variable and “_outOut” (OutPort) in auto generated code.

Set data to “_d_out”, and call “_outOut.write” function.

  def onExecute(self, ec_id):
    print "Input number: "
    self._d_out.data = long(sys.stdin.readline())
    OpenRTM_aist.setTimestamp(self._d_out)
    print "Data is %d" % (self._d_out.data)
    self._outOut.write()		
    return RTC.RTC_OK

In Python, if you use sequence, prepare an empty list, and use append function to add elements, then, set the list to “_d_out.data” variable.

  def onExecute(self, ec_id):
    OpenRTM_aist.setTimestamp(self._d_out)
    dataBuffer = [];
    print "Input 3 numbers"
    for v in range(3):
      print "Input number: "
      value = long(sys.stdin.readline())
      print "Data is %d" % (value)
      dataBuffer.append(value)
    self._d_out.data = dataBuffer;
    self._outOut.write()	
    return RTC.RTC_OK

RTC with InPort

RTC Builder

Tab Parameter Setting
Basic Module name ConsoleOut
Module description Console Out Component
Module version 1.0.0
Module vender Your name
Module category TEST
Component type STATIC
Component Kind Data Flow
Component’s activity type PERIODIC
Number of maximum instance 1
Execution Type Periodic Execution Context
Execution Rate 1.0
Abstract Not important
RTC Type Not important
Output Project ConsoleOut
Activity on_execute Checked
DataPort (InPort) PortName in (name of port)
DataType TimedLong (type of port)
VarName in (variable of buffer)
Disp. Position LEFT (direction of display)
Language and Environment Language C++, Java, Python

Coding

Edit onExecute function.



If you define InPort named “in”, you can find “m_in” and “m_inIn”.
“m_inIn” is InPort class object. You can use InPort#isNew function to check if the InPort received data (or not). If isNew returns true, you can receive data with InPort#read function.
When read function succeeded, the received data is copied to “m_in”, and you can get the data from m_in.data member.

RTC::ReturnCode_t ConsoleOut::onExecute(RTC::UniqueId ec_id)
{
  if (m_inIn.isNew())
  {
    m_inIn.read();
    std::cout << "Data is " << m_in.data << std::endl;
  }
  return RTC::RTC_OK;
}

If you use sequence, m_in.data is array. The length function (without any argument) returns the length of array received.

RTC::ReturnCode_t ConsoleSeqOut::onExecute(RTC::UniqueId ec_id)
{
  if(m_inIn.isNew()) {
    m_inIn.read();
    std::cout << m_in.data.length() << " datas received." << std::endl;
    for(int i = 0;i < m_in.data.length();i++) {
      std::cout << "Data is " << m_in.data[i] << std::endl;
    }
  }
  return RTC::RTC_OK;
}
In Java, you can find “m_in”, “m_in_val”, and “m_inIn” member variables.
You only have to know m_in (DataRef type), and m_inIn (InPort).

    @Override
    protected ReturnCode_t onExecute(int ec_id) {
    	if(m_inIn.isNew()) {
    		m_inIn.read();
    		System.out.println("Data is " + m_in.v.data); 
    	}
        return super.onExecute(ec_id);
    }

First, use isNew function to test if the data is received or not.
If read function is succeeded, m_in variable has the data.

If sequence, m_in.v.data is array.

    @Override
    protected ReturnCode_t onExecute(int ec_id) {
        if(m_inIn.isNew()) {
            m_inIn.read();
            System.out.println(m_in.v.data.length + " data received.");
            for(int i = 0;i < m_in.v.data.length;i++) {
                System.out.println("Data is " + m_in.v.data[i]);
    	    }
        }
        return super.onExecute(ec_id);
    }
In Python, “_d_in” and “_inIn” is automatically generated.
You can use _inIn.read function, and the return value is received value.

  def onExecute(self, ec_id):
    if self._inIn.isNew():
      data = self._inIn.read()
      print "Received: ", data.data
    return RTC.RTC_OK

If sequence, its quite natural for Python programmer.

  def onExecute(self, ec_id):
    if self._inIn.isNew():
      dataBuffer = self._inIn.read()
      print "Receive %d datas" % len(dataBuffer.data)
      for v in dataBuffer.data:
        print "Data is %d" % (v)
 
    return RTC.RTC_OK

Execution

Edit rtc.conf file.
corba.nameservers: localhost:2809

Then, launch name service and execute ConsoleIn / ConsoleOut.

Connection using RT System Editor

Next, let’s connect RTCs.

Select File -> “Open New System Editor”, then, drag / drop both RTCs from “Name Service View” to the editor

Drag & Drop

Drag & Drop RTC, then RTC is visualized.

Next, connect both connectors by drag/drop. An dialog will be shown, immediately after you connect.
Then select “push” in Dtataflow type.

Select Dataflow type

Select Dataflow type

Okay, you are ready to communicate.

RTCs are connected

RTCs are connected

When you activate both RTCs, you can find “Input number” in console of ConsoleIn.

Input number as you like, and then, press enter.

You can find the number you put in the console of ConsoleOut.

Sammary

What do you think of it?
You can realize the communication among RTCs.
C++: ConsoleOut
C++: ConsoleIn
Java: ConsoleInOutJ
Python: ConsoleInOutPy

Example of Sequence
C++: ConsoleSeqInOut
Java: ConsoleSeqInOutJ
Python: ConsoleSeqInOutPy

Column

subscription_type

Subscription type is very important, and you need to know if you manage the whole RT system.

Select Subscription Type

Select Subscription Type


You can select three types of subscription_type parameter.

flush

Immediately after you call OutPort#write, data is sent to InPort’s buffer. The write function blocks when the data is successfully transported.

new

The data is sent by another process, so write method does not block. This setting can select “push policy”.
ALL: all available datas in OutPort side buffer will be sent to InPort side.
FIFO: one data will be sent.
SKIP: a certain number of datas are sent.
NEW: the newest one is sent.

periodic

The data is sent periodically. You can not synchronize Sender and Receiver. If you set “push rate”, frequency of data transport can be changed, but tuning is difficult.