TIPS

TIPS을 소개합니다.

TIPS

여기에서는, OpenRTM-aist를 사용하는데 있어서의 TIPS를 소개합니다.

ARTLinux를 사용해 RT컴포넌트를 리얼타임화한다

통상 컴포넌트의 실행 컨텍스트를 ARTLinux로 리얼타임화 된 실행 컨텍스트로 바꾸는 것으로, 컴포넌트의 실행을 리얼타임화할 수 있습니다. 자세한 것은 RSJ2007에서 발표하고 있습니다.
  • 安藤 慶昭, 清水 昌幸, 尹 祐根, 神徳 徹雄, "RT컴포넌트의 리얼타임화를 실현하는 실행 컨텍스트의 확장", 제25회 일본 로봇 학회 학술 강연회 예고집, p.2I14, 2007.09, 치바공업대학,치바현

RT컴포넌트를 크로스 개발한다

OpenRTM-aist 및 RT컴포넌트를 Intel(i386) 이외의 CPU로 움직이고 싶은 경우, SH4나 PPC 등 느린 CPU에서는 컴파일에 시간이 걸려 효율적으로 개발할 수 없는 경우가 있습니다. 다른 CPU용의 OpenRTM 및 RT컴포넌트를 Intel(i386) CPU상에서 컴파일·개발하기 위한 크로스 개발 환경을 작성하면, C2D나 Quad 등 최근이 빠른 PC상에서 효율적으로 개발할 수 있습니다. 이 TIPS는 アックス의 森田씨가 제공해 주셨습니다.

Windows Vista로 NameService를 사용할 수 없는 경우

OpenRTM-aist-0.4.2를 windows vista상에서 실행하기 위해서, 스타트 메뉴로부터 NameServise를 실행해도 RTSystemEditor에서 접속할 수 없는 경우가 있습니다.

C:\Program Files\OpenRTM-aist\0.4\bin\rtm-naming.bat 를 이하와 같이 변경해 환경 변수 OMNIORB_USEHOSTNAME를 무효화해 주십시오.

 set OMNIORB_USEHOSTNAME=localhost
 ↓
 rem set OMNIORB_USEHOSTNAME=localhost

ARTLinux용의 실행 컨텍스트

ARTLinux용 실행 컨텍스트

ARTLinux상에서 OpenRTM-aist-0.4.0으로 작성한 RT컴포넌트를 리얼타임으로 실행하기 위한 방법을 설명합니다. OpenRTM-aist에서는 loadable module로서 작성한 실행 컨텍스트(ExecutionContext)을 동적으로 로드해, 컴포넌트에 바인드 하는 것으로 RT컴포넌트의 동작을 제어할 수 있습니다.

개요

OpenRTM-aist-0.2.0에서는 ARTLinux를 사용해 RT컴포넌트를 리얼타임화하는 방법으로서 이하와 같은 방법이 일시적으로 사용되고 있었습니다.
  1. rtc_active_entry 로 art_enter 를 콜
  2. rtc_active_do 로 art_wait 를 콜
  3. rtc_active_exit 로 art_exit 를 콜

OpenRTM-aist-0.4.0에서는 컴포넌트의 실행 주체(≒스렛드)는 ExecutionContext라고 하는 명시적으로 분리된 오브젝트가 되고 있어 상기와 같은 방법에서는 리얼타임화할 수 없습니다.

순서로서는, 이하와 같이 됩니다.
  1. ARTLinux용 ExecutionContext 공유 라이브러리 (ARTExecutionContext.so)의 작성
  2. RT컴포넌트의 *Comp.cpp 의 수정
  3. RT컴포넌트의 재컴파일
  4. rtc.conf의 수정
  5. RT컴포넌트의 실행

ARTLinux용 ExecutionContext 공유 라이브러리의 작성

어카이브(archive)의 다운로드

이하의 링크로부터 ARTExecutionContext의 소스를 다운로드합니다.

빌드

파일을 적당한 디렉토리에 압축을 해제해 빌드합니다. 부속의 Makefile는/usr/lib/art_syscalls.o가 존재하는 것으로서 기술되고 있습니다. art_syscalls.o가 다른 장소에 있는 경우는 Makefile를 수정해 주십시오.

 $ tar xvzf ARTExecutionContext.tgz
 $ cd ARTExecutionContext/
 $ make 

*Comp.cpp의 수정

작성 끝난 컴포넌트의 *Comp.cpp 의 앞부분을 변경합니다.

 manager->load("ArtExecutionContext.so", "ArtExecutionContextInit");
 setModuleInitProc(MyModuleInit);

setModuleInitProc의 전에 manager->load로 시작되는 위의 행을 추가합니다. 이것으로 위에서 작성한 ARTExecutionContext.so가 로드됩니다.

컴포넌트의 재컴파일

컴포넌트를 재컴파일 합니다.

 $ make -f Makefile.yourcomp

rtc.conf의 수정

rtc.conf에 이하와 같이(1)(4)를 추가합니다.

 corba.nameservers: localhost:9876
 naming.formats: Sample/%n.rtc
 logger.log_level: TRACE
 
 exec_cxt.periodic.type: ArtExecutionContext   # (1)
 exec_cxt.periodic.rate: 200                   # (2)
 manager.modules.load_path: ./                 # (3)
 manager.modules.abs_path_allowed: yes         # (4)

exec_cxt.periodic.type
ExecutionContext의 타입을 지정합니다. 사용하는 ExecutionContext는 ArtxecutionContext입니다.
exec_cxt.periodic.rate
ExecutionContext의 실행 주기를[Hz]로 지정합니다. 1 ms주기로 실행하는 경우는 1000, 5 ms주기로 실행하는 경우는 200과 같이 지정합니다.
manager.modules.load_path
모듈 로드 패스를 지정합니다. ArtExecutionContext.so가 존재하는 패스를 지정합니다. 위에서는 컴포넌트를 실행하는 디렉토리를 지정하고 있습니다.
manager.modules.abs_path_allowed
모듈 로드 패스에 절대 패스 지정을 허락하는지를 지정합니다. 우선 yes로 해주십시오.

컴포넌트의 실행

ArtExecutionContext.so 의 복사

위에서 작성한 ARTExecutionContext.so를 컴포넌트 실행 디렉토리에 복사합니다.

 $ cd YourComponentDir
 $ cp ARTExecutionContext/ARTExecutionContext.so .

실행

컴포넌트를 실행합니다.

 $ YourComponentComp

샘플

여기에서는, ArtExecutionContext를 이용한 간단한 샘플을 소개합니다.(栗原 제공)

rtc-template의 실행

rtc-template에서 컴포넌트의 모형을 생성합니다.

이하와 같이 gen.sh와 같은 파일을 생성하면, 재차 모형을 생성할 때에 편리합니다.

 $ mkdir ArtEcSample
 $ cd ArtEcSample
 $ vi gen.sh
 rtc-template -bcxx --module-name=art_ec_test   --module-desc=art ec test component --module-version=1.0.0 --module-vendor=S.Kurihara   --module-category=Category --module-comp-type=STATIC   --module-act-type=DataFlowComponent --module-max-inst=1
 
 $ sh gen.sh
  File "art_ec_test.h" was generated.
  File "art_ec_test.cpp" was generated.
  File "art_ec_testComp.cpp" was generated.
  File "Makefile.art_ec_test" was generated.
  File "README.art_ec_test" was generated.

헤더 파일의 편집

art_ec_test.h의 onExecute(), onDeactivate() 의 주석을 해제합니다.

소스 파일의 편집

이번은 onExecute() 내에서 gettimeodda()에서 취득한 시간을 파일에 쓰는 컴포넌트를 작성합니다.

[art_ec_test.cpp]

 // -*- C++ -*-
 /*!
  * @file  art_ec_test.cpp
  * @brief art ec test component
  * @date $Date$
  *
  * $Id$
  */
 
 #include "art_ec_test.h"
 
 #include <fstream>
 #include <sys/time.h>
 
 // 시간을 파일에 쓰기 위한 오브젝트
 ofstream out;
 
 static const char* art_ec_test_spec[] =
   {
     "implementation_id", "art_ec_test",
     "type_name",         "art_ec_test",
     "description",       "art ec test component",
     "version",           "1.0.0",
     "vendor",            "S.Kurihara",
     "category",          "Category",
     "activity_type",     "DataFlowComponent",
     "max_instance",      "1",
     "language",          "C++",
     "lang_type",         "compile",
     ""
   };
 
 art_ec_test::art_ec_test(RTC::Manager* manager)
   : RTC::DataFlowComponentBase(manager),
     dummy(0)
 {
   // File open
   out.open("cycle.log");
 }
 
 art_ec_test::~art_ec_test()
 {
 }
 
 /*
 RTC::ReturnCode_t art_ec_test::onActivated(RTC::UniqueId ec_id)
 {
   return RTC::RTC_OK;
 }
 */
 
 
 RTC::ReturnCode_t art_ec_test::onDeactivated(RTC::UniqueId ec_id)
 {
   // File close
   out.close();
   return RTC::RTC_OK;
 }
 
 
 RTC::ReturnCode_t art_ec_test::onExecute(RTC::UniqueId ec_id)
 {
   /****** 시간 취득과 파일에 쓰기 ***********/
   timeval tv;
   gettimeofday(&tv,0);
   out << tv.tv_usec << std::endl;
   /************************************************/
 
   return RTC::RTC_OK;
 }
 
 extern "C"
 {
  
   void art_ec_testInit(RTC::Manager* manager)
   {
     RTC::Properties profile(art_ec_test_spec);
     manager->registerFactory(profile,
                              RTC::Create<art_ec_test>,
                              RTC::Delete<art_ec_test>);
   }
   
 };
 

*Comp 파일의 편집

art_ec_testComp.cpp의 main() 함수내의manager->setModuleInitProc(MyModuleInit);의 위에 이하의 1행을 추가합니다.

 manager->load("ArtExecutionContext.so", "ArtExecutionContextInit");

컴포넌트의 실행

ART용 ExecutionContext?를 이용하기 위해서는 ARTExecutionContext?.so가 컴포넌트 실행 디렉토리에 존재해야 합니다.

 $ cd ArtEcSample
 $ cp ~/ARTExecutionContext/ARTExecutionContext.so .

이하의 방법으로 컴포넌트를 실행 후, Activate, DeActivate를 실시하면 cycle.log라고 하는 파일이 생깁니다.

 $ ./art_ec_testComp

주기 데이터

아래는 위의 컴포넌트에서 계측한 매주기의 차분 시간의 데이터입니다.
표시되고 있는 값은 마이크로 세컨드입니다.

 [exec_cxt.periodic.rate: 1000]
 1015
 1004
 997
 1001
 984
 1033
 956
 1024
 991
 981
 995
 1026
 1006
 999
 973
 1009
 1012
 999
 1010
 1002

 [exec_cxt.periodic.rate: 200]
 4997
 5022
 4977
 5010
 4994
 4998
 4992
 5013
 4993
 5004
 5015
 4979
 5006
 4996
 4990
 5009
 4999
 4998
 5007
 4998
 4984

이와 같이, ARTLinux를 이용해 기존의 컴포넌트를 리얼타임화할 수 있습니다.

RT컴포넌트의 크로스 개발

개요

OpenRTM-aist 및 RT컴포넌트를 Intel(i386) 이외의 CPU로 실행하고 싶은 경우, SH4나 PPC 등 느린 CPU에서는 컴파일에 시간이 걸려 효율적으로 개발할 수 없는 경우가 있습니다. 다른 CPU용의 OpenRTM 및 RT컴포넌트를 Intel(i386) CPU상에서 컴파일·개발하기 위한 크로스 개발 환경을 작성하면, C2D나 Quad 등 최근이 빠른 PC상에서 효율적으로 개발할 수 있습니다. 이 TIPS는 アックス의 森田씨로부터 제공되었습니다.

개발 환경

Fedora6를 추천합니다. 다른 환경에서는 빌드 스크립트가 동작하지 않을 가능성이 있습니다. 여기에서 강연회용의 VMwareImage가 이용 가능합니다.

필요한 파일을 다운로드한다

크로스 개발에 필요한 파일을 다운로드합니다.

toolchain

toolchain와는 특정의 아키텍쳐용의 빌드와 개발에 사용되는 소프트웨어 패키지의 집합체입니다. 각각에서는, SH4를 타겟 아키텍쳐로 한 개발을 상정하고 있기 때문에 SH4용의 toolchain가 필요합니다.

ACE

ACE는 OpenRTM-aist에서 필요로 하는 라이브러리입니다. SH4용으로 빌드 된 것이 필요하기 때문에 이미 PC에 ACE가 인스톨 되어 있어도, 아래에서 설명하는 자동화 스크립트로 다시 빌드 할 필요가 있습니다.

omniORB

omniORB는 OpenRTM-aist에서 필요로 하는 라이브러리입니다. SH4용으로 빌드 된 것이 필요하기 때문에 이미 PC에 omniORB가 인스톨 되어 있어도, 아래에서 설명하는 자동화 스크립트로 다시 빌드 할 필요가 있습니다.

boost

OpenRTM-aist

빌드 자동화 스크립트

이하의 빌드 자동 스크립트를 다운로드합니다. 위의 패키지의 패치 및 자동 빌드에 필요한 스크립트가 들어가 있습니다.

빌드

어카이브의 전개

우선, 이하의 3개의 디렉토리(A),(B),(C)(을)를 준비합니다.
  • (A) Build_SH4_OpenRTM.tgz를 전개해서 할 수 있는 디렉토리(Build_SH4_OpenRTM)
  • (B) OpenRTM-aist의 환경이 인스톨 되는 디렉토리
  • (C) 빌드 작업용 디렉토리

빌드 스크립트의 실행

  1. 상기의 toolchain, ACE, omniORB, boost, OpenRTM-aist의 어카이브(archive)를 디렉토리(A)안에 둔다.
  2. (A)의 디렉토리내에서, 이하와 같이./Build_SH4_SDK.sh를 실행합니다.

 $./Build_SH4_SDK.sh [(B)의 전체 경로] [(A)의 전체 경로] [(C)의 전체 경로]

스크립트의 실행이 완료되면 디렉토리(B) 내에 OpenRTM의 환경과 SH4의 toolchain, 빌드 된 ACE 라이브러리가 작성됩니다.

OpenRTM-aist-1.0.0-RELEASE에서 RC1로의 변경점

주된 변경의 개요

  • IDL에 여러가지 데이터형의 정의가 추가되었다.
  • RTObject_impl에 복수의 OutPort의 write를 정리해 호출하는 기능, 복수의 InPort의 read를 정리해 호출하는 기능이 추가되었다.
  • 포트의 콜백의 설정 방법이 변경되었다.
  • 데이터 포트의 접속시의 행동을 실행시에 변경할 수 있는 프로퍼티가 추가되었다.
  • Manager에 master/slave라고 하는 개념이 도입되었다.

coil

  • 이하의 기능이 추가
    • Process: 프로세스를 기동한다
    • Routing: 네트워크 카드가 여러개 있는 경우, 적절한 주소를 취득한다

IDL

  • BasicDataType: TimedWchar, TimedWstring가 추가.
  • ExtendedDataTypes: Point, Vector, Size 등 범용적인 형태가 정의되고 있다.
  • InterfaceDataType: Actuator, RangeData, Path 등 로봇으로 이용할 것으로 예상되는 형태가 정의되고 있다.

RTObject_impl

포트의 등록에 관한 멤버 함수의 추가

 void registerPort(CorbaPort& port);
 bool addPort(PortBase& port);
 bool addPort(PortService_ptr port);
 bool addPort(CorbaPort& port);
 bool addInPort(const char* name, InPortBase& inport);
 bool addOutPort(const char* name, OutPortBase& outport);

포트의 등록: 기존의 registerPort등의 멤버 함수와의 차이는, 등록의 성공 여부를

    반환값으로 돌려주는지 아닌지이다. 등록이 실패하는 것은 이미 같은 포트명이나
    같은 포트의 인스턴스가 등록되어 있었을 경우이다.
    그 이외의 기능은 같다.

 bool removePort(PortBase& port);
 bool removePort(PortService_ptr port);
 bool removeInPort(InPortBase& port);
 bool removeOutPort(OutPortBase& port);
 bool removePort(PortBase& port);
 bool removePort(PortService_ptr port);
 bool removePort(CorbaPort& port);

포트의 등록 해제: 기존의 deletePort등의 멤버 함수와의 차이는, 등록의 성공 여부를

    반환값으로 돌려주는지 아닌지이다. 등록이 실패하는 것은 이미 같은 포트명이나
    같은 포트의 인스턴스가 등록되어 있었을 경우이다.
    그 이외의 기능은 같다.

데이터 포트의 읽고 쓰기에 관한 멤버 함수의 추가

 bool readAll();

  • addInPort/registerInPort로 등록된 InPort에 대해서 정리하고 read를 실시한다

   class DataIn: public RTC::DataFlowComponentBase
   {
     RTC::TimedLong input_data1_;
     RTC::InPort<RTC::TimedLong> inport1_;
     RTC::TimedLong input_data2_;
     RTC::InPort<RTC::TimedLong> inport2_;
   public:
     explicit DataIn(RTC::Manager* manager):
       RTC::DataFlowComponentBase(manager),
       input_data1_(),
       inport1_("inport1", input_data1_),
       input_data2_(),
       inport2_("inport2", input_data2_)
     {
     }
 
     virtual RTC::ReturnCode_t onInitialize()
     {
       registerInPort("inport1", inport1_);
       registerInPort("inport2", inport2_);
       return RTC::RTC_OK;
     }
 
     virtual RTC::ReturnCode_t onExecute(RTC::UniqueId exec_handle)
     {
       // inport1_과 inport2_에 대해서 read를 호출한다
       const bool is_read_success = readAll();
       if (is_read_success)
       {
         std::cout << input_data1_.data << std::endl;
         std::cout << input_data2_.data << std::endl;
       }
       return RTC::RTC_OK;
     }
   };
 
 bool writeAll();

  • addOutPort/registerOutPort로 등록된 OutPort에 대해서 정리하고 write를 실시한다
   class DataOut: public RTC::DataFlowComponentBase
   {
     RTC::TimedLong output_data1_;
     RTC::OutPort<RTC::TimedLong> outport1_;
     RTC::TimedLong output_data2_;
     RTC::OutPort<RTC::TimedLong> outport2_;
   public:
     explicit DataOut(RTC::Manager* manager):
       RTC::DataFlowComponentBase(manager),
       output_data1_(),
       outport1_("outport1", output_data1_),
       output_data2_(),
       outport2_("outport2", output_data2_)
     {
     }
 
     virtual RTC::ReturnCode_t onInitialize()
     {
       registerOutPort("outport1", outport1_);
       registerOutPort("outport2", outport2_);
       return RTC::RTC_OK;
     }
 
     virtual RTC::ReturnCode_t onExecute(RTC::UniqueId exec_handle)
     {
       output_data1_.data += 2;
       output_data2_.data += 3;
 
       // outport1_과 outport2_에 대해서 write를 호출한다
       const bool is_write_success = writeAll();
       if (!is_write_success)
       {
         std::cout << "write fail" << std::endl;
       }
       return RTC::RTC_OK;
     }
   };
 
 
 void setReadAll(bool read=true, bool completion=false);
  • onExecute가 불리기 직전에 자동으로 readAll()를 호출하도록 설정한다

   class DataIn: public RTC::DataFlowComponentBase
   {
     RTC::TimedLong input_data1_;
     RTC::InPort<RTC::TimedLong> inport1_;
     RTC::TimedLong input_data2_;
     RTC::InPort<RTC::TimedLong> inport2_;
   public:
     explicit DataIn(RTC::Manager* manager):
       RTC::DataFlowComponentBase(manager),
       input_data1_(),
       inport1_("inport1", input_data1_),
       input_data2_(),
       inport2_("inport2", input_data2_)
     {
     }
 
     virtual RTC::ReturnCode_t onInitialize()
     {
       registerInPort("inport1", inport1_);
       registerInPort("inport2", inport2_);
       setReadAll(); // ★
       return RTC::RTC_OK;
     }
 
     virtual RTC::ReturnCode_t onExecute(RTC::UniqueId exec_handle)
     {
       // onExecute가 불리기 직전에 inport1_과 inport2_의 read가 불리고 있다
       std::cout << input_data1_.data << std::endl;
       std::cout << input_data2_.data << std::endl;
       return RTC::RTC_OK;
     }
   };

 void setWriteAll(bool write=true, bool completion=false);
  • onExecute가 불린 직후에 자동으로 writeAll()를 호출하도록 설정한다

   class DataOut: public RTC::DataFlowComponentBase
   {
     RTC::TimedLong output_data1_;
     RTC::OutPort<RTC::TimedLong> outport1_;
     RTC::TimedLong output_data2_;
     RTC::OutPort<RTC::TimedLong> outport2_;
   public:
     explicit DataOut(RTC::Manager* manager):
       RTC::DataFlowComponentBase(manager),
       output_data1_(),
       outport1_("outport1", output_data1_),
       output_data2_(),
       outport2_("outport2", output_data2_)
     {
     }
 
     virtual RTC::ReturnCode_t onInitialize()
     {
       registerOutPort("outport1", outport1_);
       registerOutPort("outport2", outport2_);
       setWriteAll(); // ★
       return RTC::RTC_OK;
     }
 
     virtual RTC::ReturnCode_t onExecute(RTC::UniqueId exec_handle)
     {
       output_data1_.data += 2;
       output_data2_.data += 3;
       return RTC::RTC_OK;
       // onExecute를 빠진 직후에 outport1_과 outport2_의 write가 불린다
     }
   };

그 외 처리 타이밍 등의 변경

  • RTC 초기화시에 유효하게 하는 컨피그레이션 세트를 지정하는 RTC의 프포퍼티의 키명이 변경되었다.
    • (RC1) "active_config"
    • (RELEASE) "configuration.active_config"
  • initialize내에서 on_initialize가 불려 가는 타이밍이 변경되었다.
    • (RC1) ExecutionContext를 생성하기 전
    • (RELEASE) ExecutionContext를 생성한 후
  • on_initialize내에서 onInitialize가 불려 가는 타이밍이 변경되었다.
    • (RC1) RTC의 프로퍼티 "active_config"로 지정되어 있는 컨피그레이션 세트를 유효하게 한 후.
    • (RELEASE) RTC의 프로퍼티"configuration.active_config"로 지정되어 있는 컨피그레이션 세트를 유효하게 하기 전.
  • RTObject_impl::getObjRef()가 오브젝트 레퍼런스를 duplicate 하지 않고 돌려주게 되었다. 이것에 의해, 호출한 측은 본메소드의 반환값을 RTObject_var로 받고는 갈 수 없게 되었다.
  • finalize를 외부로부터 호출할 수 없게 되었다. 호출하면 항상 PRECONDITION_NOT_MET로 에러 복귀한다. finalize는 exit를 호출하는 것으로 간접적으로 불려 간다.

포트 전반

콜백 관련

  • 이하의 콜백용 클래스가 삭제되었다.
    • OnOverflow
    • OnUnderflow
    • OnWriteTimeout
    • OnReadTimeout
      • 대신에 ConnectorListener를 사용한다
    • OnConnect
    • OnDisconnect
      • 대신에 ConnectionCallback를 사용한다
  • 데이터를 수반하는 콜백(ConnectorDataListenerType)과 데이터를 수반하지 않는 콜백(ConnectorListenerType)이 준비되어 있다.
    • ConnectorDataListenerType
      • ON_BUFFER_WRITE: 버퍼 기입시
      • ON_BUFFER_FULL: 버퍼 풀시
      • ON_BUFFER_WRITE_TIMEOUT: 버퍼 기입 타임 아웃시
      • ON_BUFFER_OVERWRITE: 버퍼 덮어쓰기시
      • ON_BUFFER_READ: 버퍼 읽기시
      • ON_SEND: InProt에의 송신시
      • ON_RECEIVED: InProt에의 송신 완료시
      • ON_RECEIVER_FULL: InProt측 버퍼 풀시
      • ON_RECEIVER_TIMEOUT: InProt측 버퍼 타임 아웃시
      • ON_RECEIVER_ERROR: InProt측 에러시
    • ConnectorListenerType
      • ON_BUFFER_EMPTY: 버퍼가 빈 경우
      • ON_BUFFER_READTIMEOUT: 버퍼가 빈 상태에서 타임 아웃 했을 경우
      • ON_SENDER_EMPTY: OutPort측 버퍼가 비어있음
      • ON_SENDER_TIMEOUT: OutPort측 타임 아웃시
      • ON_SENDER_ERROR: OutPort측 에러시
      • ON_CONNECT: 접속 확립시
      • ON_DISCONNECT: 접속 절단시
  • ConnectorDataListenerType의 콜백을 이용하기 위해서는, ConnectorDataListenerT를 계승한 리스너 클래스를 준비한다.
       class MyDataListener
         : public ConnectorDataListenerT<RTC::TimedLong>
       {
       public:
         virtual void operator()(const ConnectorInfo& info,
                                 const TimedLong& data)
         {
           // 콜백의 처리
         };
       };
  • 포트에 대해서 addConnectorDataListener로 리스너를 등록한다.
       MyDataListener *listner = new MyDataListener();
       m_port.addConnectorDataListener(ON_BUFFER_WRITE, listner);
     
  • removeConnectorDataListener로 리스너를 해제한다.
       m_port.removeConnectorDataListener(ON_BUFFER_WRITE, listner);
  • ConnectorListenerType의 콜백의 경우도 같이 ConnectorListener를 계승한 리스너 클래스를 준비한다.
       class MyConnectorListener
         : public ConnectorListener
       {
       public:
         virtual void operator()(const ConnectorInfo& info)
         {
           // 콜백의 처리
         };
       };
  • 포트에 대해서 addConnectorListener로 리스너를 등록한다.
       MyConnectorListener *listner = new MyConnectorListener();
       m_port.addConnectorListener(ON_BUFFER_EMPTY, listner);
  • removeConnectorListener로 리스너를 해제한다.
       m_port.removeConnectorListener(ON_BUFFER_EMPTY, listner);
  • PortBase에 이하의 public 멤버 함수가 추가되었다
     void setOnPublishInterfaces(ConnectionCallback* on_publish);
    • publishInterfaces의 실행"후"에 불려 가는 콜백을 설정한다. publishInterfaces가 실패하고 있어도 콜백은 불려 가는 것에 주의.
 void setOnSubscribeInterfaces(ConnectionCallback* on_subscribe);
    • subscribeInterfaces의 실행"전"에 불려 가는 콜백을 설정한다.
 void setOnConnected(ConnectionCallback* on_connected);
    • 포트 간 접속이 성공했을 경우에 불려 가는 콜백을 설정한다.
          뮤텍스가 락 되고 있기 때문에, 콜백내에서
          콜백을 설정한 포트에 대해서 get_connector_profiles나
          get_port_profile 등을 호출하면 데드 락 되는 것에 주의.
          콜백을 설정한 포트 이외의 포트에 대해서는
          뮤텍스가 락 되어 있지 않기 때문에, get_port_profile등의
          호출은 가능.
          예를 들면, 포트1으로 포트2를 접속하는 것을 생각한다.
          포트1에 setOnConnected로 콜백을 설정해 둔다.
          이 콜백내로부터 포트1에 대해서 get_port_profile등의
          호출을 실시하면 데드 락 된다. 포트2에 대해서는
          get_port_profile등을 호출할 수 있다.

 void setOnUnsubscribeInterfaces(ConnectionCallback* on_subscribe);

  • unsubscribeInterfaces의 실행"전"에 불려 가는 콜백을 설정한다.
        뮤텍스가 락 되고 있기 때문에, 콜백내에서
        접속 대상 포트의 get_connector_profiles나 get_port_profile 등을
        호출하면 데드 락 되는 것에 주의.
        setOnConnected와 달라, 콜백을 설정하고 있지 않는 포트에
        대해도 get_port_profile 등을 호출할 수 없는 것에 주의.
        예를 들면, 포트1으로 포트2를 접속하는 것을 생각한다.
        포트1에 setOnConnected로 콜백을 설정해 둔다.
        이 콜백내에서는 포트1, 포트2 모두
        get_port_profile등의 호출을 실시하면 데드 록 된다.
 void setOnDisconnected(ConnectionCallback* on_disconnected);
  • 포트간의 절단 처리의 마지막에 불려 가는 콜백을 설정한다.
        절단 처리의 도중에 어떠한 에러가 있어도 콜백은
        불려 가는 것에 주의.
        또, 뮤텍스의 락 되고 있기 때문에,
        setOnUnsubscribeInterfaces와 같이, 데드 락에 주의.
 void setOnConnectionLost(ConnectionCallback* on_connection_lost);
  • 포트 접속이 돌연 절단 되었을 경우에 불려 가는 콜백을 설정한다.
        다만, 이 콜백에 관해서는, PortBase에서는 처리의 구현을
        하고 있지 않고, 상속 클래스측에서 구현하게 되어 있다.
        현재는, OutPort에만 구현되고 있어 InPort와 CorbaPort에서는
        콜백을 설정해도 불려 갈 것은 없다.

그 외

  • PortProfile에 저장되고 있는 포트명이[RTC의 인스턴스명].[포트명]으로 변경되었다.
     다만, addPort나 registerPort등에서 포트를 RTC에 등록하고 있지 않는 상태에서는,.[포트명]이 되어 있다.
     또, addPort나 registerPort등의 호출을 onInitialize 이전(constructor등)에 실시하면,
     RTC의 인스턴스명이 확정하고 있지 않기 때문에, 포트명은 .[포트명]이 되어 버린다.
  • notify_connect내에서 에러가 발생했을 경우의 처리 방법이 변경되었다.
    • (RC1) 접속 대상의 포트 모두에 대한 publishInterfaces나 connectNext,
             subscribeInterfaces의 호출에 대해서, 도중에 1개에서도 실패했을 경우,
             즉석에서 에러 복귀한다
    • (RELEASE) 접속 대상의 포트 모두에 대한 publishInterfaces나 connectNext,
                 subscribeInterfaces의 호출에 대해서, 도중에 실패해도,
                 그대로 처리는 속행한다. 접속 대상 포트 모두에 대해서 처리를
                 한 후, 발생한 에러에 대응하는 에러 반환값을 돌려준다.
  • PortBase에 이하의 public 멤버 함수가 추가되었다
     const char* getName() const;

·PortBase의 protected 멤버 함수 eraseConnectorProfile가

 뮤텍스의 락을 실시하지 않게 되었다.

·PortBase의 이하의 멤버 함수를 호출했을 때,

 접속하고 있는 포트를 모두 체크해 무효가 된 포트가
 있으면, 절단 처리를 실시하게 되었다.
   get_port_profile()
   get_connector_profiles()
   get_connector_profile()

·포트의 프호퍼티"connection_limit"를 지정하면,

 접속수의 제한을 할 수 있게 되었다.

■데이터 포트 【콜백 관련】 ·InPort의 이하의 콜백 설정 함수가 삭제되었다.

 그 대신해, addConnectorDataListener를 사용한다.
 void setOnWrite(OnWrite<DataType>* on_write);
 void setOnWriteConvert(OnWriteConvert<DataType>* on_wconvert);
 void setOnOverflow(OnOverflow<DataType>* on_overflow);
 void setOnUnderflow(OnUnderflow<DataType>* on_underflow);

·OutPot의 이하의 멤버 함수가 삭제되었다.

 콜백의 설정은 addConnectorDataListener를 사용한다.
 bool read(DataType& value);
 void setReadBlock(bool block);
 void setWriteBlock(bool block);
 void setReadTimeout(long int timeout);
 void setWriteTimeout(long int timeout);
 void setOnOverflow(OnOverflow<DataType>* on_overflow);
 void setOnRead(OnRead<DataType>* on_read);
 void setOnReadConvert(OnReadConvert<DataType>* on_rconvert);
 void setOnUnderflow(OnUnderflow<DataType>* on_underflow);
 void setOnConnect(OnConnect* on_connect);
 void setOnDisconnect(OnConnect* on_disconnect);
 void onConnect(const char* id, PublisherBase* publisher);
 void onDisconnect(const char* id);

【접속시의 정책 설정】 ·RT System Editor로 데이터 포트를 접속할 때,

 송신 정책과 버퍼링 정책을 지정할 수 있게 되었다.

 송신 정책(접속 방식이 flush(디폴트)의 경우는 사용할 수 없다)
  - All: InPort의 버퍼에 쌓여 있는 데이터를 한 번에 모두 송신한다
  - Fifo: InPort의 버퍼에 쌓여 있는 데이터를 FIFO로 간주해(오래된 것부터 1개씩) 송신한다
  - Skip: InPort의 버퍼에 쌓여 있는 데이터를 스킵해 송신한다
  - New: InPort의 버퍼에 쌓여 있는 데이터의 최신값만을 송신한다

 버퍼링 정책
 ·버퍼 기입시에 버퍼가 풀이었던 경우의 동작을 지정할 수 있다.
  - overwrite: 덮어쓰기한다
  - do_nothing: 아무것도 하지 않는다
  - block: 블록 한다. 타임 아웃 설정가능.

 ·버퍼 읽기시에 버퍼가 빈 경우의 동작을 지정할 수 있다.
  - readback: 최신의 값을 다시 읽는다
  - do_nothing: 아무것도 하지 않는다
  - block: 블록 한다. 타임 아웃 설정가능.

·데이터 포트의 접속시의 프로퍼티에"dataport.serializer.cdr.endian"

 을 지정하면, 송수신 하는 데이터의 endian를 변경할 수 있다.
 그러나, RT System Editor는 대응하고 있지 않다.

【그 외】 ·DataPortStatus에 BUFFER_ERROR가 추가되었다.

·데이터 포트로 CORBA 대신에 TCP/IP를 이용하고 통신을 실시하는 것이

 할 수 없게 되었다.
 (TCP/IP용의 Provider/Consumer를 자작하면 가능하다고 생각된다)

·InPort::read의 반환값의 형태가 변경되었다.

 (RC1) 읽어들인 데이터
 (RELEASE) 읽을 성공 여부를 나타내는 bool

·Timed*의 데이터에 대해서 현재 시각을 부여하는 함수 setTimestamp()가 추가되었다.

·OutPort::write()로 타임 스탬프를 부여하지 않게 되었다.

·OutPot에 이하의 멤버 함수가 추가되었다.

 이것을 이용하면 1대 다접속 시에 접속마다의 write의 결과를 취득할 수 있다.
 DataPortStatus::Enum getStatus(int index);
 DataPortStatusList getStatusList();

·데이터 포트의 pull의 동작

 - InPort::isNew()는 항상 false를 돌려준다.
 - 송신측의 버퍼에 데이터가 없는 경우는, InPort::read()의 반환값이 false가 된다.
 - OutPort측의 Buffer empty policy의 설정에 의해, 버퍼가 빈 경우의 동작이 다르다.
  디폴트로는 readback이 되어 있기 때문에, 한 번 데이터를 write() 하는과 같은 값을 계속읽는다.

  데이터 포트를 push로 접속했을 경우와 pull로 접속했을 경우에서는 프로그래밍 스타일이 다르다.

 [push의 경우]
   RTC::ReturnCode_t ConsoleOut::onExecute(RTC::UniqueId ec_id) {
     if (m_inport.isNew()) {
       m_inport.read();
       // 데이터를 이용한 처리
     }
     return RTC::RTC_OK;
   }

 [pull의 경우]
   RTC::ReturnCode_t ConsoleOut::onExecute(RTC::UniqueId ec_id) {
     bool ret = m_inport.read();
     if (ret == true) {
       // 데이터를 이용한 처리
     }
     return RTC::RTC_OK;
   }

■서비스 포트 【접속시의 정책 설정】 ·CorbaPort의 접속에 대해 ConnectorProfile::properties에 "port.connection.strictness"라고 하는 프로퍼티를 설정할 수 있게 되었다. 이 프로퍼티에는 "strict" 나 "best_effort"를 설정한다.

 CorbaPort.h에서 인용
  * strict: 모든 컨슈머(consumer)로 지정한 참조가 존재해, 한편 네로잉에도
  *         성공해 컨슈머(consumer)에게 적절히 세트 할 수 있었을 경우에게만 Port
  *         사이의 접속을 확립한다.
  *
  * best_effort: 네로잉등에 실패했을 경우에서도, 에러를 돌려주는 것
  *         구 Port 간의 접속을 확립한다.

【그 외】 ·CorbaPort로, 접속중에 RTC를 Activate, Deactivate 해, 재차 Activate 하면 컨슈머(consumer)측으로부터 액세스 할 수 없는 문제가 해결되었다.

■Manager 관계 Manager에 마스터와 슬레이브라고 하는 관계를 할 수 있었다. 자세한 것은[openrtm-users 01099]의 安藤씨의 해설을 참조.

【rtc.conf에게 주는 프로퍼티의 변경】 ·Manager의 프로퍼티(rtc.conf에게 주는 프로퍼티)로 변경이 있었다.

 "corba.endpoint"
   사용할 수 없게 되었다.대신에"corba.endpoints"를 사용하게 되었다.

 "manager.is_master"
   NO로 하면 Manager의 CORBA 오브젝트를 네이밍 서비스에
   등록하지 않게 되었다.

 "manager.corba_servant"
   NO로 하면 Manager의 CORBA 오브젝트를 생성하지 않는다.

 "manager.is_master"
   YES이면, Manager의 프로퍼티"corba.master_manager"로
   지정되어 있는 포트 번호를 ORB의 엔드 포인트로서
   추가하게 되었다.

 "manager.shutdown_on_nortcs"
   YES의 경우,"manager.is_master"NO이면, 프로세스내의 RTC가 0개에
   된 타이밍에 Manager가 자동 종료하게 되었다.
   다만,[openrtm-users 01149]의 패치를 대는 것.

【RTC 기동시의 커멘드 라인 인수의 옵션의 추가】

 -a
   지정하면, Manager의 CORBA 오브젝트를 생성하지 않는다.
   다만, ManagerConfig::parseArgs()에 버그가 있기 위해,
   이 옵션을 지정해도 Manager의 CORBA 오브젝트의
   생성이 유효하게 된다.("maanger.corba_servant"로 스펠 미스)
   SVN의 최신 소스에서는 수정되고 있는 모양.
 -d
   지정하면, Manager가 마스터가 된다.
 -o
   Manager의 프로퍼티를 추가할 수 있다.
   이 옵션에 이어 (프로퍼티의 키):(프로퍼티의 값)라고 쓴다.
   예를 들면, -o test.property:100
 -p
   Manager의 프로퍼티"corba.endpoints"에 포트 번호를 추가한다.
   예를 들면, -p 50000

【Manager의 내부 구현의 변경】 ·RC1에서는 미구현이었던 ModuleManager::getLoadableModules()가 구현되었다.

 → Manager::getLoadableModules()를 사용할 수 있게 되었다.

·Manager::setModuleInitProc()로 설정한 함수가 실행된다

 타이밍이 변경되었다.
 Manager::activateManager()로 실행되는 것 자체는 변경되어 있지 않다.
 그러나, Manager의 프로퍼티"manager.components.precreate"로
 지정된 RTC를 기동하는 처리와의 차례가 변경되고 있다.
 (RC1) "manager.components.precreate"의 RTC를 생성한 후
 (RELEASE) "manager.components.precreate"의 RTC를 생성하기 전

·Manager에 RTC의 가비지 콜렉션과 같은 기능이 추가되었다.

 RTC를 exit 하면, Manager가 1초 주기에 exit 된 RTC를 delete 한다.
 다만, 버그 있어.[openrtm-users 01149]의 패치를 대는 것.
 또, createComponent로 생성한 RTC가 on_initialize로 실패하면
 그 RTC는 delete 되지 않고, 메모리 리크 한다.
 RTC의 initialize가 실패하면 RTC를 exit 하지만,
 exit는 initialize가 성공하지 않았다고 처리를 거부하기 위해, Manager::notifyFinalized가 불리지 않고, Manager의 RTC 가비지 콜렉션이 일하지 않기 때문에.

·Manager가 RTC를 삭제할 때, delete를 직접 사용하는 것이 아니라,

 Manager::registerFactory로 등록된 RTC 삭제 함수를 사용하도록 수정되었다.

·Manager::load()로, 제2 인수의 초기화 함수명이 빈 경우의 처리가 추가되었다.

 초기화 함수명이 빈 경우는, 제1 인수의 모듈명에"Init"를 부여했다
 초기화 함수명으로 모듈의 로드를 시도하게 되었다.

·Manager::createComponent로, 지정한 RTC를 생성하는 Factory가

 등록되지 않은 경우, Manager의 프로퍼티"manager.modules.load_path"로
 지정한 패스로부터, 지정한 RTC를 생성 가능한 모듈을 검색해,
 자동 로드하는 기능이 추가되었다.

【IDL 인터페이스의 변경】 ·IDL 인터페이스 RTM::Manager가 변경되었다.

 (추가)
 boolean is_master();
 ManagerList get_master_managers();
 RTC::ReturnCode_t add_master_manager(in Manager mgr);
 RTC::ReturnCode_t remove_master_manager(in Manager mgr);
 ManagerList get_slave_managers();
 RTC::ReturnCode_t add_slave_manager(in Manager mgr);
 RTC::ReturnCode_t remove_slave_manager(in Manager mgr);
 (삭제)
 Manager get_owner();
 Manager set_owner(in Manager mgr);
 Manager get_child();
 Manager set_child(in Manager mgr);

·ManagerServant::get_loadable_modules(),

 ManagerServant::get_loaded_modules(),
 ManagerServant::get_factory_profiles()는, 본래,
 자신의 것 뿐만이 아니라, 슬레이브의 모듈도
 취득할 수 있는 메소드같지만,
 현재의 실장에서는 자신의 모듈 밖에 취득할 수 없다.