컨피그레이션 (기초편)

컨피그레이션이란

로보트 시스템을 구축하데 시스템의 외부환경, 사용 상황이나 개별 디바이스, 로봇의 특성에 따라 작성하는 프로그램 내의 파라메터를 변경하는 일이 종종 있습니다. 단순한 실험을 하기 위한 간단한 프로그램에서는 파라메터를 하드 코드하고 변경할 때마다 직접 고쳐 써, 컴파일하는 것으로 대처할 수 있을지도 모릅니다. 좀 더 진행하여 파라메터를 파일 등에서 읽거나 커멘드 라인 인수로 건네는 등의 궁리를 하는 것으로 재이용성은 훨씬 높아집니다. 하나의 프로그램을 용도에 따라 재이용하기 위해서는 이러한 파라메터를 내장시키지 말고 외부화하는 것이 매우 중요하게 됩니다.

RT컴포넌트에 의해 구축된 RT시스템에서는 다양한 사람이 작성한 다양한 컴포넌트가 협조하여 동작하기 때문에, 코어 로직 내부에서 사용되는 파라메터를 유저가 자유롭게 정의하여 실행시에 외부에서 변경하기 위한 기능이 준비되어 있습니다. 이것을 컨피그레이션(기능)이라고 부릅니다. 컨피그레이션은 복수의 파라메터 세트를 갖을 수 있고, 파라메터 세트를 일제히 바꿔 넣을 수도 있습니다. 파라메터를 미리 변경가능하게 해두는 것으로 RTC를 다양한 시스템에서 간단히 재이용할 수 있습니다.

configuration_example_ko.png
컨피그레이션의 예

이 섹션에서는 RT컴포넌트의 중요한 기능의 하나인 컨피그레이션에 대해 구조와 실제 사용법에 대해 설명합니다.

컨피그레이션의 구조

아래의 그림은 컨피그레이션의 대략의 구조를 나타내고 있습니다.

configuration_functionality_ko.png
컨피그레이션의 구조

파라메터의 이름의 페어를 컨피그레이션 파라메터 라고 부릅니다. 하나의 컴포넌트는 복수의 컨피그레이션 파라메터를 정의할 수 있고, 그 집합을 컨피그레이션 세트라고 부릅니다.

더욱이 하나의 컴포넌트는 복수의 컨피그레이션 세트를 가질수 있고 그 중 하나의 컨피그레이션만이 실제의 파라메터 값이 됩니다. 이 컨피그레이션 세트를 액티브 컨피그레이션 이라고 부릅니다. 컨피그레이션 세트는 이름을 붙일 수 있어 그 이름에 의해 구별됩니다.

외부 툴(RTSystemEditor나 rtshell 등)을 사용해서 각각의 파라메터 혹은 액티브하게 컨피그레이션 세트를 변경할 수 있습니다. 컨피그레이션의 내용은 컨피그레이션에 연결되어 있는 변수(파라메터 변수) 에 반영되어, RT컴포넌트 내의 로직에서 사용할 수 있습니다. 이렇게 로직 내부에서 사용되는 파라메터를 외부에서 용이하게 변경할 수 있도록 하는 것으로 컴포넌트의 재사용성을 높일 수 있습니다.

  • 컨피그레이션: 컴포넌트 내의 파라메터를 외부화하기 위한 RTC의 기능
  • 컨피그레이션 파라메터: 실제로 컴포넌트 내의 외부화 된 파라메터. 키와 값으로 구성된다.
  • 컨피그레이션 세트: 키와 값의 리스트로 구성되는 파라메터의 리스트. RTC는 복수의 세트를 가질 수 있다.
  • 컨피그레이션 세트명: 컨피그레이션 세트에 붙여진 이름. 세트는 각각 이름으로 구별된다.
  • 액티브 컨피그레이션: RTC는 복수의 컨피그레이션 세트를 가질 수 있고 그 중 실제로 파라메터에 반영되는 유효한 세트를 액티브 컨피그레이션이라고 부른다.
  • 파라메터 변수: 컨피그레이션 파라메터에 연결되어진 변수. 컨피그레이션의 내용이 변경되면 변수에 대입되어 있는 값이 변경된다.

변수 타입이 있는 언어에서는 컨피그레이션 파라메터는 그 언어에서 이용가능 하다면 어떤 타입이라도 사용할 수 있습니다. 물론 타입이 없는 언어에서도 같지만, 중요한 점은 이러한 파라메터를 외주에서 설정할 때 그 값은 문자열에 의해 주어지는 것입니다.

컨피그레이션은 문자열을 각각의 파라메터형으로 변환해 실제의 변수에 세트합니다. 구조체나 배열 등 문자열에서 데이터에 간단하게 변환 불가능한 데이터 타입이라도 변환 함수를 정의하는 것으로 어떤 타입의 데이터라도 똑같이 취급할 수 있습니다. 이것은 미리 IDL정의가 필요한 데이터 포트나 서비스 포트와는 크게 다른 점입니다.

파라메터를 정의

RT컴포넌트 내에서 사용하는 파라메터를 정의하는 방법에는 몇가지가 있습니다.

  • RTCBuilder에서 컴포넌트 설계시에 정의
  • rt-template에서 컨피그레이션 파라메터를 정의
  • 수동으로 필요한 코드를 작성

이하에서 각각의 방법에 대해 설명합니다.

RTCBuilder에 의한 정의

컨피그레이션 파라메터를 정의하는 가장 간단한 방법은 RTC의 설계 툴인 RTCBuilder로 RTC설계시에 컨피그레이션 파라메터를 정의하는 것입니다.

아래의 그림은 RTCBuilder의 컨피그레이션 정의 화면입니다. 이 화면에서 필요한 파라메터를 정의하는 것으로 컨피그레이션 파라메터를 이용하기 위해 필요한 코드가 언어를 불문하고 자동적으로 생성됩니다.

configuration_rtcb00_ko.png
RTCBuilder의 설정 화면

컨피그레이션 파라메터를 이용하기 위해서는 RTCBuilder의 컨피그레이션 탭을 누르고 파라메터 리스트 옆의 Add버튼을 누릅니다. 그러면 컨피그레이션 파라메터가 한개 추가되므로 적당한

  • Name (필수)
  • Type (필수)
  • Default Value (필수)

를 입력합니다.

Name은(디폴트로는 conf_name0 등으로 되어 있으므로) 그 파라메터의 성질 을 단적으로 나타내는 알기 쉬운 이름을 붙여 주십시오. 드롭 다운 리스트에서 선택할 수 있는 데이터 타입은 각 언어에 대해 적절히 변환되어 정의 됩니다. Python 등 명시적으로 형선언이 필요하지 않은 언어에서는 여기에 설정된 형은 코드 상에 나타나지 않을지도 모릅니다.

위에서도 서술한 것처럼 컨피그레이션 파라메터는 값을 문자열로서 주고 문자열을 특정 데이터 타입으로 변환하는 것으로 다양한 형의 파라메터에 대응 가능 합니다. 단, 외부에서 문자열로서 값이 업력되기 때문에 변환 불가능한 문자열 등 부정한 파라메터 입력이 있을 경우, 변환시 에러가 발생하는 경우도 있습니다. 여기서 설정된 디폴트 값은 설정된 값의 변환이 부정한 경우에 대신 사용되는 값입니다.

이외에도 필수가 아닌 항목으로는 이하의 항목이 있습니다. 필요에 따라 입력해 주십시오.

  • Variable name: 변수이름으로 사용하는 문자열. 빈 경우는 위에 Name에 입력한 내용이 사용됩니다.
  • Unit: 이 파라메터의 단위. 현재로서는 사람이 읽는 이외로는 사용되고 있지 않습니다.
  • Constraint: 이 파라메터의 제약 조건을 부여합니다. 이 조건은 RTSystemEditor에서 사용됩니다. 연속적인 값의 경우는 부등호, 열거값의 경우는 ,(콤마)로 구분 등 지정할 수 있습니다.
  • Widget: RTSystemEditor에서 파라메터를 조작할때 사용되는 컨트롤. text, slider, spin, radio중 선택할 수 있습니다.
  • Step: 위의 Widget이 slider 나 spin인 경우 스텝을 지정합니다.

자세한 내용은 화면 우측의 힌트나 RTCBuilder의 메뉴얼을 참조해 주십시오.

rtc-template에 의한 정의

rtc-template는 커맨드 라인에서 사용하는 컴포넌트 템플릿 제네레이터입니다. rtc-template에서 컨피그레이션을 사용하려면 이하와 같이 지정합니다.

    /usr/local/bin/rtc-template -bcxx --module-name=ConfigSample 
    --module-type=DataFlowComponent 
    --module-desc=Configuration example component --module-version=1.0 
    --module-vendor=Noriaki Ando, AIST --module-category=example 
    --module-comp-type=DataFlowComponent --module-act-type=SPORADIC 
    --module-max-inst=10 --config=int_param0:int:0 
    --config=int_param1:int:1 --config=double_param0:double:0.11 
    --config=double_param1:double:9.9 
    --config=str_param0:std::string:hoge 
    --config=std_param:std::string:dara 
    --config=vector_param0:std::vector<double>:0.0,1.0,2.0,3.0,4.0
 
    # 실제로는 1행으로 입력하던지 계속 문자를 행의 마지막에(UNIX에서는 \, Windows에서는 ^)을 입력해 주십시오.

이것은 샘플에 부속되어 있는 ConfigSample에서의 지정 예입니다.

 --config=<명칭>:<데이터 형>:<디폴트 값>

와 같이 지정합니다. 데이터 형에 대해서는 그 언어에서 사용하는 데이터 형을 지정합니다만, 프리미티브 형 이외에서는 제대로 동작하지 않거나 수동으로 수정이 필요한 경우가 있습니다.

수동에 의한 정의

별로 추천하지 않습니다만 수동으로도 컨피그레이션 파라메터를 정의 하는 것이 가능합니다. 새로 파라메터를 추가하고 싶은 경우 등에 유효합니다만 문서나 RTC.xml파일 등을 갱신하지 않으면 제3자가 이 RTC를 사용 하는 경우에 사양과 구현의 정합성을 이해할 수 없거나 혼란을 초래할 가능성 이 있기 때문에 주의해 주십시오.

단, 컨피그레이션이 어떻게 선언되어 사용되는지를 이해하는 것은 의미가 있기 때문에 여기서 설명합니다.

컨피그레이션을 사용하려면 아래의 작업이 필요합니다.

컨피그레이션 파라메터(이하 파라메터)의 용도, 이름, 데이터 타입을 결정

위에서 설명한 것처럼 컴포넌트의 어느 부분에서 파라메터를 사용하는지 또는 그 파라메터의 특징을 나타내는 이름과 구현시의 데이터 타입명(타입이 있는 언어의 경우)을 결정합니다.

파라메터의 변수를 컴포넌트의 헤더(private/protected)에 선언

RTCBuilder나 rtc-template에서 생성한 파일이면, 이하와 같은 태그로 둘러싸인 부분이 있습니다. 여기에 컨피그레이션 파라메터를 위한 변수를 선언합니다.

  // Configuration variable declaration
  // <rtc-template block="config_declare">
 
  // </rtc-template>

위의 ConfigSample의 예라면 이하와 같이 됩니다.

  // Configuration variable declaration
  // <rtc-template block="config_declare">
  int m_int_param0;
  int m_int_param1;
  double m_double_param0;
  double m_double_param1;
  std::string m_str_param0;
  std::string m_str_param1;
  std::vector<double> m_vector_param0;
  
  // </rtc-template>

컴포넌트의 구현 파일의 static 변수 <컴포넌트 명>_spec[]에 파라메터의 선언과 디폴트 값을 추가

컨피그레이션 파라메터는 컴포넌트 내에서 Properties라는 데이터 저장소에 저장되어 관리됩니다. 이 Properties안에서는,

 conf.<컨피그레이션 세트 명>.<파라메터 명>

이라는 키로 컨피그레이션 파라메터를 저장하고 있습니다. 디폴트 값으로서 default라는 컨피그레이션 세트명이 예약되어 있어 디폴트 값은 모두 이 default컨피그레이션 세트로서 정의됩니다.

위의 ConfigSample의 경우 이하와 같이 추가 합니다.

 // Module specification
 // <rtc-template block="module_spec">
 static const char* configsample_spec[] =
   {
     "implementation_id", "ConfigSample",
     "type_name",         "ConfigSample",
     "description",       "Configuration example component",
     "version",           "1.0",
     "vendor",            "Noriaki Ando, AIST",
     "category",          "example",
     "activity_type",     "DataFlowComponent",
     "max_instance",      "10",
     "language",          "C++",
     "lang_type",         "compile",
     // Configuration variables
     "conf.default.int_param0", "0",
     "conf.default.int_param1", "1",
     "conf.default.double_param0", "0.11",
     "conf.default.double_param1", "9.9",
     "conf.default.str_param0", "hoge",
     "conf.default.str_param1", "dara",
     "conf.default.vector_param0", "0.0,1.0,2.0,3.0,4.0",
  
     ""
   };
 // </rtc-template>

Configuration variables 이하의 부분이 디폴트 컨피그레이션 세트 의 정의가 됩니다.

각 변수를 초기화자로 초기화

RTCBuilder나 rtc-template로 생성된 변수는 생성자의 초기화자에 의한 초기화는 하지 않지만 가능하면 모든 변수는 생성자의 초기화자로 초기화하는 편이 좋습니다. 또한, 각변수에 디폴트 값이 세트되는 것은 onInitialize()함수의 bindParameter()함수가 불려진 뒤이기 때문에 원칙으로는 그 이전에는 사용해서는 안됩니다.

bindParameter()함수로 파라메터와 변수를 바인드

마지막으로 변수와 파라메터의 이름, 디폴트 값, 변환 함수를 바인드 하는 것으로 단순한 변수를 컨피그레이션 파라메터로 합니다. RTObject클래스의 멤버 함수(메소드)인 bindParameter()를 사용합니다.

 bindParameter(<파라메터 이름(문자열)>, 변수, <디폴트 값(문자열)>, <변환 함수>)

위의 ConfigSample(C++의 예)에서는 이하와 같이 됩니다.

  // <rtc-template block="bind_config">
  // Bind variables and configuration variable
  bindParameter("int_param0", m_int_param0, "0");
  bindParameter("int_param1", m_int_param1, "1");
  bindParameter("double_param0", m_double_param0, "0.11");
  bindParameter("double_param1", m_double_param1, "9.9");
  bindParameter("str_param0", m_str_param0, "hoge");
  bindParameter("str_param1", m_str_param1, "dara");
  bindParameter("vector_param0", m_vector_param0, "0.0,1.0,2.0,3.0,4.0");
  
  // </rtc-template>

이렇게 하는 것으로 각 변수와 컨피그레이션 파라메터가 바인드 되어 RTSystemEditor 등에서 이러한 변수를 조작할 수 있는 컨피그레이션 파라메터가 이용 가능하게 됩니다.

또한, bindParameter()에 파라메터로 주는 변환 함수는 임베디드 형에 대해서는 상기의 예와 같이 불필요하고 특히 명시적으로 줄 필요는 없습니다. 하지만 독자적인 구조체나 복잡한 형등을 컨피그레이션 파라메터로서 사용하고 싶은 경우는 문자열로 그러한 형태로의 변환을 정의해 여기에 줄 필요가 있습니다. 변환 함수의 자세한 내용은 뒤에서 설명합니다.

파라메터를 사용

파라메터를 사용하는 것은 매우 간단합니다. 지금까지 설명한 대로 컨피그레이션 파라메터로서 선언된 변수를 단순히 사용하는 것 뿐입니다. 단, 사용에 대해서는 몇가지의 조건이 있어, 이 조건을 지켜서 사용해야 합니다.

변수를 사용할 수 있는 콜백 함수

컨피그레이션 변수는 특정의 콜백 함수 (onXXX())내에서 밖에 사용할 수 없습니다. 외부에서부터의 컨피그레이션 변수의 변경은 비동기적으로 행해집니다. 일반적으로 이러한 경우는 뮤텍스 등으로 변수에의 배타 액세스 제어를 할 필요가 있습니다만, 이것을 실현하려면 컴포넌트 개발자도 각 변수에의 액세스 시에 뮤텍스 보호를 해야합니다. 이것을 회피하기 위해 OpenRTM-aist에서는 외부에서의 컨피그레이션의 변경은 콜백 함수의 외부에서 행해지게 되어 있습니다.

사용할 수 있는 콜백 함수는 이하와 같습니다.

  • onInitialize() (※)
  • onActivated()
  • onExecute()
  • onStateUpdate()
  • onDeactivate()
  • onAborting()
  • onError()
  • onReset()
  • onFinalize() (※)

거의 모든 콜백 함수안에서 컨피그레이션 파라메터를 사용 할 수 있습니다. 다만, onInitialize()에 대해서는 bindParameter()를 하기 전에는 당연히 컨피그레이션 파라메터를 사용할 수 없습니다. 또, onFinalize()안에서는 그 호출 직전의 컨피그레이션 파라메터에 대해 변경이 반영되지 않을 가능성이 있습니다.

변수는 읽기 전용

컨피그레이션 파라메터의 변수는 컴포넌트의 외부에서 변경 되어 그 값이 파라메터용 변수에 대입됩니다. 하지만 파라메터용 변수에 onExcute()등 내부 함수내에서 써도 외부에서 보이는 파라메터의 값은 반영되지 않습니다.

이와 같이, 변수의 값은 변경은 일방통행이므로 컴포넌트 내부로부터의 변수에 쓰기는 의미가 없습니다. 컨피그레이션 변수는 read only로 사용합시다.

값이 정상인가 항상 체크

컨피그레이션 파라메터 값은 위에서 설명한 대로 외부에서 문자열로서 주어진 것을 변환 함수로 변환한 것이 실제 사용되는 변수에 대입됩니다. 문자열이기 때문에 본래 수치가 대입되어야 할 곳에 문자열이 대입되거나 short int로 정의된 변수에 상한 이상의 크기의 수치가 대입되는 것도 있을 수 없습니다. 따라서, 받은 측에서는 변수가 상정되어 있는 값의 범위내에 들어가 있는지, 있을 수 없는 값이 대입되어 있지는 않은지 프로그램 상에서 사용전에 항상 체크하는 것을 추천합니다.

파라메터를 설정

컨피그레이션 파라메터는 몇개의 세트를 갖고 실행시에 그것들을 동시에 변경할 수 있다는 것을 위에서 설명했습니다. 한편, RTCBuilder나 rtc-template에서 컴포넌트를 설계하는 시점에서는 디폴트 컨피그레이션 세트 밖에 정의 할 수 없었습니다. 여기에서는 컨피그레이션 세트의 사용법에 대해 설명합니다.

컴포넌트 설정 파일

디폴트 컨피그레이션 세트는 소스 코드에 적용됩니다. 같은 방법으로 다른 컨피그레이션 세트도 원리적으로는 소스 코드에 적용하는 것이 가능합니다. 그러나 RTC컨피그레이션 기능의 목적은 소스 코드를 변경하지 않고 용도에 따라 파라메터를 변경하는 것으로 하나의 컴포넌트를 다양한 용도로 사용하는 것이기 때문에, 소스 코드에 다른 컨피그레이션 세트를 적용하는 것은 본말 전도입니다.

컨피그레이션 세트는 컴포넌트의 컨피그레이션 파일로 줄 수 있습니다. 컴포넌트의 설정을 하는 파일에는 rtc.conf가 있습니다만 이것은 주로 컴포넌트를 관리하는 미들웨어를 위한 설정 파일로 컴포넌트를 위한 설정 파일은 rtc.conf내에 이하와 같이 지정할 수 있습니다.

 corba.nameservers: localhost
 naming.formats: %h.host_cxt/%n.rtc
 example.ConfigSample.config_file: configsample.conf

example.ConfigSample.config_file의 부분이 컴포넌트의 컨피그레이션 파일의 지정 부분입니다. 컨피그레이션 파일을 지정하는 부분은 이하와 같습니다.

 <카테고리명>.<모듈명>.fongi_file: <파일명>

또, 컴포넌트의 모듈명 대신에 인스턴스명을 주는 것도 가능합니다.

 <카테고리명>.<인스턴스명>.fongi_file: <파일명>

따라서, 인스턴스 마다 다른 컨피그레이션 파일을 주는 것도 가능합니다.

 example.ConfigSample0.config_file: consout0.conf
 example.ConfigSample1.config_file: consout1.conf
 example.ConfigSample2.config_file: consout2.conf

컨피그레이션 세트의 설정

컨피그레이션 파일안에는 사용하고 싶은 컨피그레이션 세트를 기술합니다.

 configuration.active_config: mode1
 
 conf.mode0.int_param0: 12345
 conf.mode0.int_param1: 98765
 conf.mode0.double_param0: 3.141592653589793238462643383279
 conf.mode0.double_param1: 2.718281828459045235360287471352
 conf.mode0.str_param0: mode0
 conf.mode0.str_param1: foo
 conf.mode0.vector_param0: 0.0,0.1,0.2,0.3,0.4
 
 conf.mode1.int_param0: -999
 conf.mode1.int_param1: 999
 conf.mode1.double_param0: 297992458
 conf.mode1.double_param1: 2.97992458e+8
 conf.mode1.str_param0: mode1
 conf.mode1.str_param1: AIST
 conf.mode1.vector_param0: 1,2,3,4,5,6,7,8,9
 
 conf.__widget__.int_param0: slider.1
 conf.__widget__.int_param1: spin
 conf.__widget__.double_param0: slider.0.1
 conf.__widget__.double_param1: text
 conf.__widget__.str_param0: radio
 conf.__widget__.str_param1: text
 conf.__widget__.vector_param0: text
 
 conf.__constraints__.int_param0: 0<=x<=150
 conf.__constraints__.int_param1: 0<=x<=1000
 conf.__constraints__.double_param0: 0<=x<=100
 conf.__constraints__.double_param1: 
 conf.__constraints__.str_param0: (default,mode0,mode1,foo,bar,radio)
 conf.__constraints__.str_param1: 
 conf.__constraints__.vector_param0: 

액티브 컨피그레이션 세트의 지정

맨 처음의 행 configration.active_config에 액티브한 컨피그레이션 세트 명을 지정하고 있습니다. 여기에서는 mode1이라는 세트명으로 당연히 존재하는 세트명을 지정할 필요가 있습니다.

 configuration.active_config: mode1

컨피그레이션 세트의 설정

다음으로 conf.mode0로 시작하는 파라메터의 리스트가 있습니다만 이것이 세트명 mode0의 컨피그레이션 파라메터의 리스트입니다. 지정의 방법은 소스 코드와 거의 같이

 conf.<세트명>.<파라메터명>: <디폴트값>

로 되고 있습니다. 반드시 존재하는 모든 컨피그레이션 파라메터에 대해 지정해 주십시오. 지정되지 않은 경우는 디폴트 값이 사용됩니다. 그 다음으로 conf.mode1로 시작하는 파라메터의 리스트가 있습니다만 이것도 mode0같이, mode1이라는 세트명의 파라메터의 설정입니다.

확장 기능

다음에 conf, _ _widget_ _으로 시작하는 설정 리스트가 있습니다. 이것은 RTSystemEditor에서 사용되는 특수한 파라메터입니다. RTCBuilder로 컨피그레이션 파라메터를 설정할 때 widget을 지정할 수 있는 것을 위에서 설명했지만 여기에서 설정된 내용이 conf._ _widget_ _으로 설정됩니다. slider, radio, spin, text의 4종류를 설정할 수 있고 각각 RTSystemEditor에서 컨피그레이션 파라메터 설정 다이얼로그를 열었을때 슬라이더, 라디오버튼, 스핀 버튼, 텍스트 박스로 파라메터를 조작할 수 있습니다.

 conf.__widget__.<파라메터명>: 위젯명

또한, 슬라이더(slider)를 설정한 경우,

 conf.__widget__.int_param0: slider.5

와 같이 하는 것으로 슬라이더의 조작폭을 5로 할 수 있습니다. 현재, 이 조작폭을 소수로 하는 것은 불가능합니다. 단, 이후의 버전업에서 개선될 가능성이 있습니다. 또한, 스핀 버튼은 그 성질상 항상 1입니다. int 등 정수치의 파라메터에만 사용하는 것을 추천합니다.

이것들 conf._ _widget_ _파라메터를 설정한 경우, 그 아래의 conf._ _constraints_ _파라메터를 설정할 필요가 있습니다. conf._ _constraints_ _파라메터는 값의 범위를 설정하기 위한 특수한 파라메터로 지정 방법으로는 슬라이더나 스핀 버튼을 위한 가변수 x와 등호, 부등호를 이용한 다음과 같은 지정 방법이나,

 conf.__constraints__.int_param0: 0<=x<=150

radio 버튼에 의한 괄호와 콤파에 의한 리스트에 의한 이하와 같은 지정 방법이 있습니다.

 conf.__constraints__.str_param0: (default,mode0,mode1,foo,bar,radio)

이 외에도 conf._ _constraints_ _파라메터에는 제약의 기술 방법잉 있습니다만, 위젯에 사용되는 제약 조건의 지정 방법은 현재 상기의 2개 뿐입니다.

변환 함수에 대해

C++등에서는 int나 douboe등의 임베디드 형에 대해서는 특히 변환 함수를 지정할 필요가 있습니다. 한편, 구조체나 STL컨테이너 등 유저 독자적인 형을 이용하고 싶은 경우도 있습니다. 이 경우, 문자열에서 각각의 형으로의 변환을 어떻게 할까를 bindParameter()에 함수로서 줄 필요가 있습니다.

변환 함수에 대해서는 이하와 같이 각 언어별로 룰이 있습니다. 이하는 각 언어별 방법을 기술합니다.

C++의 경우 변환 함수

C++에 있어서 bindParameter의 프로토 타입 선언은

 template <typename VarType>
     bool bindParameter(const char* param_name, VarType& var,
                const char* def_val,
                 bool (*trans)(VarType&, const char*) = coil::stringTo)
               

와 같이 되어 있어 제4인수의 trans에 적당한 함수 포인터를 주는 것으로 문자열에서 해당형에의 변환이 행해집니다. 디폴트로는 coil라이브러리 함수의 stringTo()함수가 주어지고 있습니다. 스스로 이 stringTo()에 해당하는 변환 함수를 쓰고, 함수 포인터를 줄 수도 있습니다만 coil::stringTo()함수 자체도 함수 템플릿으로 되어 있어, std::stream에 대한 operator>>()함수

 std::istream& operator>>(std::istream&, T)

가 정의되어 있다면 자동적으로 이것을 사용해 문자열에서 특정형으로의 변환이 행해집니다.

즉, std::cin >> <어떤형의 변수>와 같이 쓰는 방법이 가능하다고 한다면 그 형은 operator>>()가 정의되어 있어 특히 변환 함수를 쓰지 않아도 컨피그레이션 의 파라메터로서 사용할 수 있습니다.

만약, 변환 함수가 없는 경우, 예를 들어 이하와 같은 콤마 구분의 수치 열

 0.0,1.0,2.0,3.0,4.0

을 std::vector<double>로 변환하기 위한 변환 함수는,

 #include <istream>
 #include <ostream>
 #include <vector>
 #include <string>
 #include <coil/stringutil.h>
 
 template<typename T>
 std::istream& operator>>(std::istream& is, std::vector<T>& v)
 {
   std::string s;
   std::vector<std::string> sv;
   is >> s;
   sv = coil::split(s ,",");
   v.resize(sv.size());
   for (int i(0), len(sv.size()); i < len; ++i)
     {
       T tv;
       if (coil::stringTo(tv, sv[i].c_str()))
         {
           v[i] = tv;
         }
     }
   return is;
 }

이와 같이 구현할 수 있습니다. 또한, 이것은 OpenRTM-aist C++버전의 샘플, ConfigSample 컴포넌트의 소스에 포함되는 VectorConver.h입니다.

이것을 bindParameter()가 호출되는 소스(예를 들면, ConfigSample 컴포넌트 라면 ConfigSample.cpp), 통상은 컴포넌트의 구현 소스로 include해 주면, 컴파일시에 컴파일러가 판단하여 적당한 변환 함수가 사용됩니다.

Java의 경우 변환 함수

Java의 경우 변환 함수라는 것을 별도로 주는 것이 아니라, 컨피그레이션 변수의 홀더 클래스에 있어 정의되는 stringFrom() 메소드에 문자열 로부터 실제의 형으로 변환을 기술합니다.

이하에 OpenRTM-aist java버전의 ConfigSample에 정의되어 있는 콤마 구분 수치값을 Vector형으로 변환 하기 위한 변환 함수를 나타냅니다.

 package RTMExamples.ConfigSample;
 
 import java.io.Serializable;
 import java.util.Vector;
 
 import jp.go.aist.rtm.RTC.util.ValueHolder;
 
 public class VectorHolder  implements ValueHolder, Serializable {
 
     /**
      * Vector형 데이터 설정값
      */
     public Vector value = null;
 
     /**
      * 디폴트 생성자
      *
      */
     public VectorHolder() {
     }
 
     /**
      * 생성자
      *
      * @param initialValue 초기값
      *
      */
     public VectorHolder(Vector initialValue) {
         value = new Vector(initialValue);
     }
 
     /**
      * 문자열에서 Vector형르로 변환해 설정
      *
      * @param def_val 설정값 문자열 표현
      *
      */
     public void stringFrom(String def_val) throws Exception {
         value = new Vector();
         String values[] = def_val.split(",");
         for( int intIdx=0;intIdx<values.length;intIdx++ ) {
             value.add(values[intIdx]);
         }
     }
     /**
      * 설정값의 취득
      *
     * @return 설정값
      *
      */
     public Vector getValue(){
         return value;
     }
     /**
      * 설정값을 문자열로 변환
      *
     * @return 변환 문자열
      *
      */
     public String toString(){
         StringBuffer retVal = new StringBuffer();
         while(value.iterator().hasNext()) {
             retVal.append(value.iterator().next());
             if(value.iterator().hasNext()) retVal.append("'");
         }
         return retVal.toString();
     }
 }

Python의 경우 변환 함수

Python버전 OpenRTM-aist에서는 디폴트에서는 기본형과 그 리스트에 대응해 그 외의 변환이 필요하면, bool stringTo(type, string)와 같은 함수를 정의하고 bindParameter()의 제4인수로 함수 오브젝트를 건네줍니다.

무엇을 파라메터로 하는가?

RT컴포넌트를 작성하는데 무엇을 컨피그레이션 파라메터로 하면 좋은 것인지 생각해 봅시다.

어느 파라메터가 있어 그것을 외부로부터 변경하려면 몇개의 방법이 생각될 수 있습니다. 데이터 포트를 이용해 변경하는 방법, 서비스 포트를 이용해 변경하는 방법 그리고 컨피그레이션을 이용해 변경하는 방법입니다.

컨피그레이션 기능은 컴포넌트 내부의 파라메터를 변경하기 위한 기능입니다. 따라서 로직내의 파라메터는 컨피그레이션 파라메터로서 외부에서 변경할 수 있도록 해야 합니다. 그러나 어떤 변경량을 컨피그레이션 파라메터로 해야 하는가 그렇지 않은 것인가 망설이는 경우 도 있다고 생각합니다. 여기에서는 그러한 경우에 대해 잠시 생각해 보겠습니다.

갱신 빈도

컨피그레이션 파라메터는 일반적으로 시스템이 움직이기 시작하기 전에 1번, 혹은 설정 변경이 필요하게 된 경우만 외부에서 파라메터를 주기 위해 이용합니다. 갱신 빈도가 시스템의 라이프 사이클상에서 1회내지는 몇차례정도면 컨피그레이션을 사용하는 것이 좋을 것입니다.

또한 위에서도 설명했지만 컨피그레이션은 툴이나 어플리케이션에서는 문자열로서 주어지기 때문에 컴포넌트내에서 각각의 형태로 변환됩니다. 변환에는 어느 정도(최근의 PC에서는 수 us에서 수백 us정도입니다만) 시간이 걸리기 때문에 예를 들면 1ms주기로 데이터를 보내는 용도로는 적합하지 않습니다. 그럼 그 정도의 빈도로 파라메터를 변경할 수 있는 것일까요? 실제로 사용할 때에는 파라메터의 수나 컴퓨터, 네트워크의 속도에도 의존하지만, 수백ms 또는 그 이상의 빈도에서는 사실상 문제없이 파라메터를 변경할 수 있습니다. 단, 그와 같은 주기적으로 몇번이나 값을 변경할 필요가 있는 것은 데이터 포트를 사용 해야 할 것입니다.

데이터인가 파라메터인가?

예들 들면, 원격지의 센서에서 정기적으로 데이터를 중앙 서버에 보내는 시스템을 생각해봅시다. 데이터는 1시간에 1회 보내져 서버측에서는 그것을 로그에 기록한다고 합니다. 이 때, 그 데이터는 데이터 포트를 사용해 보내야 할 것인가? 아니면 서비스 포트를 사용해야만 하는 것인가, 혹은 컨피그레이션을 사용해야 할 것인가?

보내지는 것은 센서의 데이터이기 때문에 데이터 포트를 이용해 보내는 것이 가장 적합하다고 할 수 있습니다. 컨피그레이션은 외부에서 파라메터를 설정하기 위한 구조이므로 비록 갱신 빈도가 1시간에 1번이라도 이 데이터를 컨피그레이션으로 컴포넌트에 전송하는 것은 부적절하다고 할 수 있습니다. 단, 데이터 포트에서는 실현될 수 있는 클라이언트와 서버측의 복잡한 교환(트랜잭션 등)을 실현하고 싶은 경우는 서비스 포트가 사용될지도 모릅니다.

서비스인가 파라메터인가?

데어터 포트로 해야 하는가 컨피그레이션으로 해야 하는가는 실제로 그다지 망설일 것은 아닐 것 입니다. 한편, RTC로직내에서의 파라메터를 서비스 포트에서 변경해야 할 것인가 컨피그레이션 파라메터로 해야 할 것인가 망설이는 경우는 많을 것으로 생각합니다.

컴포넌트가 어떤 종류의 전형적이고 어느 정도 결정된 기능을 제공하는 경우, 그 기능은 서비스 포트의 인터페이스에 의해 외부에 제공됩니다. 서비스 인터페이스에서는 대상의 상태를 취득하거나 설정・모드・파라메터를 변경하거나 하기 위한 오퍼레이션을 제공합니다. 상태의 취득은 예외지만, 설정을 하거나 모드・파라메터를 변경하거나 하는 기능은 컨피그레이션과 매우 닮았습니다.

결국은 어디에서 설정해도 큰 차이는 없습니다만, 대상으로 하는 RTC의 기능이 이미 서비스 인터페이스로서 정의되어 있거나 상태의 취득과 설정이 필요하게 되는 등 어는 정도 복잡한 기능을 제공하는 경우, 서비스 인터페이스를 매개로한 조작이 적합하다고 말할 수 있습니다. 그 이외의 간단한 파라메터・ 모드 등의 설정에는 컨피그레이션을 이용하면 좋을 것입니다.

정리

여기에서는 컨피그레이션 기능에 대한 정의 방법이나 사용법에 대해 설명하였습니다. 로직내의 파라메터는 컴포넌트의 재사용성을 향상 시키기 위해 가능한한 이 기능을 사용해 외부화 해야 합니다. 무엇을 컨피그레이션 파라메터로 해야 하는가, 해서는 안되는가 라는 것에 대해서도 주의를 기울일 필요가 있습니다. 컨피그레이션 기능을 유효하게 사용하면 작성하는 컴포넌트도 재사용성이 높아질 것입니다.

ダウンロード

最新バージョン : 2.0.1-RELESE

統計

Webサイト統計
ユーザ数:2210
プロジェクト統計
RTコンポーネント307
RTミドルウエア35
ツール22
文書・仕様書2

Choreonoid

モーションエディタ/シミュレータ

OpenHRP3

動力学シミュレータ

OpenRTP

統合開発プラットフォーム

産総研RTC集

産総研が提供するRTC集

TORK

東京オープンソースロボティクス協会

DAQ-Middleware

ネットワーク分散環境でデータ収集用ソフトウェアを容易に構築するためのソフトウェア・フレームワーク