[openrtm-users 01328] OpenRTM-aist-1.0.0-RELEASEにおけるRC1からの変更点
Hiroyuki NAKAMOTO
nakamoto @ sec.co.jp
2010年 6月 23日 (水) 11:44:01 JST
OpenRTM-aistユーザの皆さん
株式会社セックの中本です。
OpenRTM-aistは、前バージョンのOpenRTM-aist-1.0.0-RC1版から
RELEASE版にバージョンアップされて、様々な機能追加や向上、
バグフィックスがおこなわれています。
ユーザの皆さんの中には、先日、旭川でおこなわれたROBOMEC2010での
チュートリアルやポスター講演などで、OpenRTM-aist-1.0.0-RELEASE版
の新機能や変更点について、お聞きになった方もいらっしゃるかと
思います。
しかし、それ以外の方は、前バージョンのOpenRTM-aist-1.0.0-RC1版
からRELEASE版で何がどれくらい変ったのか、ご存知ない方もまだ多いか
と思います。
そこで、弊社の池添や小田桐が中心となって、独自に
OpenRTM-aist-1.0.0-RELEASEにおけるRC1からの変更点を
まとめてみました。
以下、長文になりますが、皆さんのご参考になればと思い、
MLに投稿させていただきます。
ご質問等ありましたら、このMLもしくは私宛にご連絡いただければと
思います。情報共有できそうなオープンな話題はこのML宛でお願い
いたします。
また、内容に誤りなどがあれば、適宜ご指摘いただければ幸いです。
OpenRTM-aist-1.0.0-RELEASEにおけるRC1からの変更点(文責:株式会社セック)
--- 主な変更概要 ----------------------------------------------------
・IDLに様々なデータ型の定義が追加された。
・RTObject_implに、複数のOutPortのwriteをまとめて呼び出す機能、
複数のInPortのreadをまとめて呼び出す機能が追加された。
・ポートのコールバックの設定方法が変更された。
・データポートの接続時の振舞いを実行時に変更できる
プロパティが追加された。
・Managerにマスター/スレーブという概念が導入された。
--- 詳細 ------------------------------------------------------------
■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以前(コンストラクタなど)で行うと、
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"
を指定すると、送受信するデータのエンディアンを変更できる。
しかし、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: すべてのコンシューマに指定した参照が存在し、かつナローイン
* グにも成功しコンシューマに適切にセットできた場合にのみ Port
* 間の接続を確立する。
*
* best_effort: ナローイング等に失敗した場合でも、エラーを返すことな
* く Port 間の接続を確立する。
【その他】
・CorbaPortで、接続中にRTCをActivate、Deactivateし、再度Activateすると
コンシューマ側からアクセスできない問題が解消された。
■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()は、本来、
自分のものだけでなく、スレーブのモジュールも
取得できるようなメソッドのようだが、
現在の実装では自分のモジュールしか取得できない。
以上
--
/**********************************************************
株式会社セック 開発本部 第四開発部 (宇宙先端システム担当)
ADR: 150-0031 東京都渋谷区桜丘町22-14 NESビル
TEL: 03-5458-7743 FAX : 03-5458-7726
URL: http://www.sec.co.jp
中本 啓之 [Hiroyuki NAKAMOTO]
E-Mail: nakamoto @ sec.co.jp (office)
***********************************************************/
======================================================================
この電子メールの内容および添付されている情報は、機密情報であると同時に、
宛先として意図した特定の受信者のみに送信いたしております。当方の誤送信
等により、心当たりのない方が受信された場合は、大変お手数ですが、受信さ
れましたメール内容は削除していただきますようお願いいたします。
======================================================================
openrtm-users メーリングリストの案内