2011年12月31日土曜日

よいお年を!


あと2時間ほどで2011年もおしまいです。

2010年ほどは記事を書けませんで、ここの情報も古いものとなりつつありますが、
来年もほそぼそと続けていくつもりですのでよろしくお願いします。

少なくとも以下のリリース時には記事を書きたいですね〜。

来年もよろしくお願いします!!

Fuerte Turtle (Mar 2012) (フォルテタートル)

  • Ubuntu Lucid
  • Ubuntu Oneiric
  • Ubuntu Precise
  • C++03
  • Boost 1.40
  • Lisp SBCL 1.0.x
  • Python 2.6

Groovy Galapagos (Aug 2012) (グルーヴィーガラパゴス)

  • Ubuntu Oneiric
  • Ubuntu P
  • System libraries TBD

2011年12月23日金曜日

RTミドルウェアコンテスト行ってきた

本日(2011年12月23日)に行われたRTミドルウェアコンテストに
完全に僭越ながら審査員として行ってきました!

みんなスーツの中、私は仕事じゃないので私服で審査してきました。
結果は公式に任せるとして、非常に楽しくすごさせていただきました。

RTミドルウェアとROSはいわばライバル関係で、
日本人でありながら何故かその敵側を応援?しちゃっている私ですが、
みなさん暖かく迎えてくださいました。

全体的な印象としては

  • ysugaさんすげー
  • 暖かく、いい雰囲気(使ってくれてありがとう、という人が多い)
  • 教育や学生の発表が多い
  • みんなWindowsが好き
  • ドキュメントが超丁寧


このブログらしきことを書くと、いくつかROSに似たコンセプトのものがありました。




「移動ロボットのソフトウェア開発のための屋内環境シミュレータRTC」
www.openrtm.org/openrtm/ja/project/RTMContest2011_1115
これはstageっぽい。人もシミュレーションに入れられるところが違う。

ysugaさんの
「RTno (汎用マイコンボードarduinoでRTコンポーネント対応デバイスを作るためのライブラリ)」
これも同じようなコンセプトのものがROSにあります。


「初心者向けシステム開発支援用RTC」
これはまるっきりrxplotです。
データをオンラインでグラフ化してくれます。

RTMはとっつきにくい、といっている方が何人かいました。
ROSの方がシンプルなので始めるのは少しは簡単かもしれないと思いました。

RTMの審査員をやってみて思ったのは、ROSとの比較で言うと、
  • 依存関係を考慮した配布・ビルド方法がもう少し楽になるといいと思う。rospack・rosmake・rosdepは非常に強力。
  • 自動生成したソースやら、すべてを1つのフォルダに入れて配っている人がいる気がする。もう少しソースの配置とかのルールを決めたほうがいいと思う。
  • RTC以外でライブラリを配る文化がもっと欲しい。PCLも最初はROSだったけど今はROSを切り離した。
  • ROSはドキュメントはプロむけ。RTMは親切過ぎないか心配。インストールや使い方はむつかしすぎるのをドキュメントでカバーしようとし過ぎなのかも?




なんにせよ、日本のロボット界ではソースを配る文化がなかったから、それを大幅に改善したRTミドルウェアプロジェクトの貢献は大きいと思った。

以上偉そうに好き勝手書きました。
誤解・間違い等あると思いますので、コメントください。


2011年12月9日金曜日

テレプレゼンスロボットの作り方

Makeに持っていったロボットの中身を軽く紹介しようと思います。

まず全体構成は↓のようになっています。
基本的にいままでつくってきたノードをrosbridgeでブラウザから動かしています。

roombaは前に自作したotl_roombaパッケージのもの、lv2_armはアーム用に作ったノード、usb_camはboshのもの、battery_checkerはこの前紹介したノードでPCのバッテリーチェックをします。jtalk_nodeは日本語をしゃべるノードです。
いずれも公開済みです。

ブラウザでアクセスすると以下のように表示されます。
ぐるぐるのところでルンバの速度を出力、スライダやボタンでロボットのカメラ操作、
バッテリ残量を右上のアイコンで表示(@tera_kojiさんに作ってもらいました)、
テキストボックスに文字を書くとロボットがしゃべってくれます。
画面の上には大きくカメラ動画が流れます。
javascript/HTML5で動的なページにしています。
HTMLやjavascriptにはまったく詳しくないので苦労しました。


rosbridgeはsocketやwebsocketでROSプロトコルをしゃべってくれるサーバーで、javascriptからROSを簡単に使えます。
rosbridgeはsubversionの最新版がおすすめです。安定版だとfirefoxだとうまく動きません。

画像を動画で表示する方法は、

HTMLに以下のように書いて、


  <img src="img/camera_dummy.jpg" name="camera" width="320" height="240"/>


javascriptに以下のような感じで書きます。


    connection.addHandler('/usb_cam/image_raw',
                          function(msg) {
                            document.camera.src=msg.uri;
                          });

これだけで/usb_cam/image_rawがガンガン送られてくれば動画になります。

まあ、そんな感じです。


例によって以下のリポジトリにおいておきました。整理もしていないので見せられる状態にないですが、ジョイスティックの部分とか、出せるように整理したいです。

2011年12月8日木曜日

Make Tokyo Meeting 07ありがとう

Make Tokyo Meeting 07通称MTM07の出展が無事終わりました。

このblogの読者に直にあえてうれしかったです。
PCの前からロボットを動かしてくださったみなさん、ありがとうございました。
(完成度が低くて申し訳ないです)

FRISK Roombaも買っていただきありがとうございました。
(快く一緒に参加してくださった@longjie0723さんありがとうございました!)
http://orientalrobotics.blogspot.com/2011/12/mtm07.html

紹介記事がありますので紹介します。
http://ascii.jp/elem/000/000/654/654252/index-6.html

Makeは本当に面白いプロジェクトがいっぱいで、すごく刺激になり、楽しい2日間でした。
ゆっくり見てまわるのもいいけど、また出たいな。

2011年12月3日土曜日

MTM07参加中!

Make Tokyo Meeting 参加中!!
にてロボット遠隔操作&Makeの体験ができるぞ!

2011年11月27日日曜日

MTM07参加します!

MTM07(http://www.oreilly.co.jp/mtm/07/)に出展します。

出展名はOTL++で、Oriental Robotics (http://orientalrobotics.blogspot.com/)さんといっしょにやります。
タイトルはDIYロボティクスとかにした気がします。

目玉はFRISK Roomba。フリスクケースにルンバ操作用Bluetoothモジュールが入っています。
http://orientalrobotics.blogspot.com/2011/02/friskroomba.html

こいつとKinectがあればROSの自律移動も試せるし、いろいろ遊べます。
私がこれまでに上げた動画でもこれを使っています。


Kinectでもなんでもつながります。

パソコンからプログラム余裕です。



あとはテレプレゼンスロボットを持って行きますので、「東京の会場までいけないよ」という人は自宅からMTM07に参加できちゃいます!
ブラウザから操作可能にしていますので後ほどアドレスを書きますので乞うご期待。


他にもいろいろ持っていくので、ロボット好きなひとは是非遊びに来てくださいね。

2011年11月20日日曜日

PC (Linux)のバッテリ残量を調べる

PC(Linux)のバッテリ容量をプログラムから知りたいことがあったのでPythonで作ってみました。
例によって参考程度になればと貼っておきます。
他にもっといい方法あれば教えてください。

一応ノードも作りました。

#! /usr/bin/env python

import re

class AcpiChecker():
    """read /proc/acpi/battery/*** files for check the PC's battery"""
    def __init__(self, battery_name):
        self._info_path = "/proc/acpi/battery/" + battery_name + "/info"
        self._state_path = "/proc/acpi/battery/" + battery_name + "/state"
    def get_capacity(self):
        f = open(self._info_path)
        for line in f:
            match = re.search(r'^last full capacity:\s*(\d+)', line)
            if match:
                capacity = match.groups()[0]
        f.close()
        return capacity

    def get_state(self):
        f = open(self._state_path)
        for line in f:
            match = re.search(r'^remaining capacity:\s*(\d+)', line)
            if match:
                state = match.groups()[0]
        f.close()
        return state

    def get_rate(self):
        return float(self.get_state()) / float(self.get_capacity())

if __name__=='__main__':
    checker = AcpiChecker('BAT0')
    print checker.get_rate()

ノードはこんな感じでてきとーに作ってみました。


#! /usr/bin/env python

import roslib
roslib.load_manifest('otl_battery_checker')

import rospy
from std_msgs.msg import Float64
from battery_check import AcpiChecker

class BatteryCheckerNode():
    """check battery and publish the charge rate"""
    def __init__(self, battery_name='BAT0'):
        self._checker = AcpiChecker(battery_name)
        self._pub = rospy.Publisher('/pc/battery_rate', Float64)
    def proc(self):
        msg = Float64()
        msg.data = self._checker.get_rate()
        self._pub.publish(msg)

if __name__=='__main__':
    rospy.init_node('pc_battery_checker')
    battery_name = 'BAT0'
    if rospy.has_param('~device'):
        battery_name = rospy.get_param('~device')
    check = BatteryCheckerNode(battery_name)
    rate = rospy.Rate(1)
    while not rospy.is_shutdown():
        check.proc()
        rate.sleep()


参考にしたサイト

2011年11月19日土曜日

RT ミドルウエアコンテスト 2011 参加(ただしお金だけ)

突然ですが、RTミドルウェアコンテストに参加することにしました。

ただし、ミドルウェアはまじめに書いたこと無いので協賛のほうです。(こんなんで審査していいんだろうか)
http://www.openrtm.org/rt/RTMcontest/2011/award.html
勢いでつい本名で出してしまいました。

一応このブログに関係あるっぽくしようと思って、「グローバルスタンダード賞」としました。
ROSに負けない、国際的に認められそうなモジュールがあるといいなぁ。

2011年11月6日日曜日

キーポン届いた!

アメリカ在住の @kunikku92 さんからMy Keeponが届いたよ!

開封の儀式!



キターーー!!!

うしろはこんな感じ。


上から
さあ出てらっしゃい。

おおおおお!!!


  説明書もおしゃれ


ちょっと動かして見ました。
単三電池8本必要です。
構造がひどくて入れるの超大変でした。
動画で後半手拍子していますが、音楽に合わせて踊ります。


Willowグッズももらっちゃった!!やったー!!!
ありがとう!!!
下の光ってる奴はPR2チョコですね。なんと。。。


ありがとう @kunikku92 !!!

2011年10月12日水曜日

トランスフォーマー作ってみた

今日はROSでも僕の作品でもないものの紹介です。
会社のイベントにアイデアコンテストというものがありまして、
今年のテーマが「未来の車」でした。

私たちのチームでいろいろ考えた結果できた車がこれです。

  1. ロボットアームを収納し変身
  2. ヘリを収納し発射
  3. アームでヘリをキャッチしてドッキング!
というオモシロロボットカーです。

アームでは、車から降りないで駐車券を取ったり、ドライブスルーを受け取ったりできます。
ヘリでは渋滞のときに先を見に行ったり、ヘリのカメラで本当のアラウンドビューができます。

ドッキングは男の夢です。
社内コンテストは優勝はできませんでしたが、結構満足行くものが出来ました。
自慢です。

2011年9月8日木曜日

ROS Electricのインストール(PCL1.1との共存)

さそっくelectricをインストールしようとしたのですが、依存関係が満たせないとのエラーになりました。(PCL1.1をスタンドアロンで入れたUbuntu 10.04で、ROS diamondbackが入った状態です。)

しぼっていくと以下のエラーが原因のようです。

依存: libeigen3-dev (= 3.0.1-1+ros4~lucid) しかし、3.0.2-1lucid3 はインストールされようとしています


これはスタンドアローンのPCLとの競合が原因のようです。
まずPCLを削除します。(ROS側で同じバージョンの1.1が入るので削除してもいい??でしょう)

$ sudo apt-get remove libpcl-1.1 libeigen3-dev

次に以下のファイルを削除するか、拡張子を変更するか、中身を"#"でコメントアウトします。
/etc/apt/sources.list.d/v-launchpad-jochen-sprickerhof-de-pcl-lucid.list

そして
$ sudo apt-get update
$ sudo apt-get install ros-electric-desktop-full

で入るはずです。
競合してしまうのは非常に残念ですね。

ROS Electric on OSX (Lion)

ROS ElectricをMac(Lion)に入れようとしましたが、rosconsoleのビルドでこけています。

調べたら以下のパッチがあったのでこれを使ってみたらうまく行きました。
https://code.ros.org/trac/ros/attachment/ticket/3626/ros_comm-1.6.2-rosconsole_clang_osx.patch

以上メモでした。

iheart roboticsさんからTシャツもらった

iheart roboticsさんからROS Tシャツとiheartroboticsグッズを貰いました。

エアメールで頂きました。

みなさんもblogを一度は見たことがあると思います。
Tシャツちょっと長いけどうれしい!

さっそくみんな自慢しましたがここでも自慢させてください。
周りには通じる人少ないんで。


お返しに折り紙の本でも贈ろうかと思っています。

2011年9月2日金曜日

joint_state_publisherメモ(再)

以前joint_state_publisherを紹介しました。
http://ros-robot.blogspot.com/2010/11/jointstatepublisher.html

http://www.ros.org/wiki/joint_state_publisher

詳しいやり方を書かなかったので自分のためのメモです。

まず、joint_state_publisherをゲットします。
そのためにはmercurialというソフトを必要としますので、いれましょう。

$ sudo apt-get install mercurial

次に以下のコマンドでjoint_state_publisherを取得します。

$ hg clone https://kforge.ros.org/robotmodel/visualization

そうしたら、hoge_descriptionというパッケージにurdf/hoge.xmlというurdfファイルを作ったとすると、以下のようなlaunchファイルを用意して、
パラメータにファイルを読み込ませ、joint_state_publisherを駆動し、robot_state_publisherを動かし、rvizで表示します。
joint_state_publisherがsensor_msgs/JointStateを発行し、それをrobot_state_publisherがtfに変換します。それをrvizが表示するのです。

<launch>
  <param name="robot_description" textfile="$(find hoge_description)/urdf/hoge.xml"/>
  <param name="use_gui" value="true"/>
  <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />
  <node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher" />
  <node name="rviz" pkg="rviz" type="rviz"/>
</launch>


2011年9月1日木曜日

ROS Electric Emys release

Electric がリリースされました。
http://www.ros.org/wiki/electric

Diamondbackからの変更点のうち私が気になったものをざっと見てみましょう。


  • arm navigation (アームのプランニング系)1.0。
    • やっとアーム系がまともに使えるように
  • Interactive markers (rvizで物体に触れるようになる)
    • rvizでインタラクティブに操作できるように
  • PCL1.1 
    • 最新版が使えるようになりました
  • Android
    • javaによる実装のrosjavaがはいりました
  • tf
    • 最大100倍早くなったそうです。
  • sensor_msgs/Joy
    • joy/Joyメッセージがsensor_msgsに格上げです
  • eigen, opencv2, yaml_cppなどがUbuntu nativeのものを利用するように
  • Unary stackの導入
    • スタックかつパッケージというUnary stackができた!
    • リリース単位のstackと機能単位のpackageという矛盾を解消するようです
というくらいですかね。
まだインストールはしていません。

2011年8月28日日曜日

m3pi robotを買った

@longjie0723 さんがm3pi robotというものを買うと言っていたので
きっと面白いものだろうと思って買ってみました。
(@longjie0723さんありがとうございます。)
http://www.pololu.com/catalog/product/2153

流行りの(ちょっと古い?)mbedというマイコンが載った小型ロボットです。
mbedの特徴はブラウザでプログラムが書ける、Ether使える、USBホスト機能ありなどですかね。
センサはライントレース用の光センサがついています。
いろいろ拡張ができそうです。

手のひらサイズでものすごく速く動きます。
とりあえず試しにLCDにOTLと表示したり、LEDつけて暴れさせたりして遊んでみました。


プログラムもC++で書けて非常に簡単です。

既存のロボットだと7万円〜30万円くらいしますから(もちろんセンサ数とか全然違うかもしれませんが)
プログラマブルな小型ロボットとしてはいい感じじゃないでしょうか?

2011年8月25日木曜日

Point Cloud Libraryを試す(その5:ユークリッドクラスター抽出)

いい加減PCLも飽きてきましたが、これもやっちゃいましょう。
クラスタリングです。
画像処理でもラベリングは結構使うと思います。
それの3D版です。

Euclidean Cluster Extraction
http://pointclouds.org/documentation/tutorials/cluster_extraction.php#cluster-extraction

こちらのチュートリアルのほうがシンプルですが、私は可視化したかったので↓のように少し改造してビューワを付けました。



$ wget http://dev.pointclouds.org/attachments/download/157/table_scene_lms400.pcd


して、以下をcluster_extraction.cppとして保存です。


#include <pcl/ModelCoefficients.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/features/normal_3d.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/kdtree/kdtree.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/visualization/cloud_viewer.h>


int
main (int argc, char** argv)
{
  // Read in the cloud data
  pcl::PCDReader reader;
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
  reader.read ("table_scene_lms400.pcd", *cloud);
  std::cout << "PointCloud before filtering has: " << cloud->points.size () << " data points." << std::endl; //*

  // Create the filtering object: downsample the dataset using a leaf size of 1cm
  pcl::VoxelGrid<pcl::PointXYZ> vg;
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);
  vg.setInputCloud (cloud);
  vg.setLeafSize (0.01, 0.01, 0.01);
  vg.filter (*cloud_filtered);
  std::cout << "PointCloud after filtering has: " << cloud_filtered->points.size ()  << " data points." << std::endl; //*

  // Create the segmentation object for the planar model and set all the parameters
  pcl::SACSegmentation<pcl::PointXYZ> seg;
  pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
  pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_plane (new pcl::PointCloud<pcl::PointXYZ> ());
  pcl::PCDWriter writer;
  seg.setOptimizeCoefficients (true);
  seg.setModelType (pcl::SACMODEL_PLANE);
  seg.setMethodType (pcl::SAC_RANSAC);
  seg.setMaxIterations (100);
  seg.setDistanceThreshold (0.02);

  int i=0, nr_points = cloud_filtered->points.size ();
  while (cloud_filtered->points.size () > 0.3 * nr_points)
    {
      // Segment the largest planar component from the remaining cloud
      seg.setInputCloud(cloud_filtered);
      seg.segment (*inliers, *coefficients); //*
      if (inliers->indices.size () == 0)
	{
	  std::cout << "Could not estimate a planar model for the given dataset." << std::endl;
	  break;
	}

      // Extract the planar inliers from the input cloud
      pcl::ExtractIndices<pcl::PointXYZ> extract;
      extract.setInputCloud (cloud_filtered);
      extract.setIndices (inliers);
      extract.setNegative (false);

      // Write the planar inliers to disk
      extract.filter (*cloud_plane); //*
      std::cout << "PointCloud representing the planar component: " << cloud_plane->points.size () << " data points." << std::endl;

      // Remove the planar inliers, extract the rest
      extract.setNegative (true);
      extract.filter (*cloud_filtered); //*
    }

  // Creating the KdTree object for the search method of the extraction
  pcl::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::KdTreeFLANN<pcl::PointXYZ>);
  tree->setInputCloud (cloud_filtered);

  std::vector<pcl::PointIndices> cluster_indices;
  pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;
  ec.setClusterTolerance (0.02); // 2cm
  ec.setMinClusterSize (100);
  ec.setMaxClusterSize (25000);
  ec.setSearchMethod (tree);
  ec.setInputCloud( cloud_filtered);
  ec.extract (cluster_indices);

  int j = 0;
  float colors[6][3] ={{255, 0, 0}, {0,255,0}, {0,0,255}, {255,255,0}, {0,255,255}, {255,0,255}};
  pcl::visualization::CloudViewer viewer("cluster viewer");
  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_cluster(new pcl::PointCloud<pcl::PointXYZRGB>);
  pcl::copyPointCloud(*cloud_filtered, *cloud_cluster);
  for (std::vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it)
    {
      for (std::vector<int>::const_iterator pit = it->indices.begin (); pit != it->indices.end (); pit++) {
	cloud_cluster->points[*pit].r = colors[j%6][0];
	cloud_cluster->points[*pit].g = colors[j%6][1];
	cloud_cluster->points[*pit].b = colors[j%6][2];
      }
      std::cout << "PointCloud representing the Cluster: " << cloud_cluster->points.size () << " data points." << std::endl;
      std::stringstream ss;
      ss << "cloud_cluster_" << j << ".pcd";
      writer.write<pcl::PointXYZRGB> (ss.str (), *cloud_cluster, false); //*
      j++;
    }
  viewer.showCloud (cloud_cluster); 
  while (!viewer.wasStopped())
    {
      sleep (1);
    }


  return (0);
}

するとこんな感じです。


ちなみに元データはこんな感じ。テーブル上面と床が削除されています。


少しだけコードを読むと、
最初にポイントクラウドをファイルから読み込み、pcl::VexelGridを使ってダウンサンプリングしています。
ダウンサンプリングのチュートリアルもありますが簡単なので飛ばしました。
setLeafSizeで10mm刻みのグリッドでサンプリングしていますね。

次に前回やった平面検出で平面を削除しています。
複数の平面検出をどうやるのかと思ったら、検出した領域を削除して、削除したもに対してもう一度検出することでやっているみたいです。
while(...)のところです。

で、今回のキモはpcl::KdTreeを使ってEuclideanClusterEtractionしているところです。
setClusterToleranceでマージする最大距離を指定して、最小、最大のパーティクル数を指定しているようです。

CMakeListx.txtはいつもと同じです。


cmake_minimum_required(VERSION 2.8 FATAL_ERROR)

project(cluster_extraction)

find_package(PCL 1.1 REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable (cluster_extraction cluster_extraction.cpp)
target_link_libraries (cluster_extraction ${PCL_LIBRARIES})

ここまでで、机の上にある物体をラベリングして認識することができるようになりました。
あとはフィルタのチュートリアルでもやればひと通り終わりかな?

大体感じはつかめたのでPCL本体はこれくらいにしておきましょう。

これで少しは面白いことができるかもしれません。

次はROSとのからみを見てみます。

2011年8月24日水曜日

Point Cloud Libraryを試す(その4:平面抽出)

今回はポイントクラウドから平面を抽出します。

その前に、前回使ったPointXYZRGBの色の部分がfloat rgbとなっていて気になったので調べてみました。

// pack r/g/b into rgb
 uint8_t r = 255, g = 0, b = 0;    // Example: Red color
 uint32_t rgb = ((uint32_t)r << 16 | (uint32_t)g << 8 | (uint32_t)b);
 p.rgb = *reinterpret_cast<float*>(&rgb);
↑のような感じで使うみたいです。
悪名高きreinterpret_castか!と思ったら、
ver.1.1.0からはr,g,b変数も使えるみたいで、
point.r = 255;
point.g = 100;
point.b = 10;

みたいに指定できるようです。


PCLのAPIリファレンスはこちらです。
Point Cloud Library (PCL): PCL API Documentation

という小ネタを挟みまして、今回は平面検出です。

↓のようにPointCloudから平面っぽいところを切りだしてくれるはずです。

チュートリアルはこちら

チュートリアルにあるコードは簡単なんですが、ビューワが付いていないので、ビューワを付けてみました。
以下をplanar_segmentation.cppとして保存してください。

#include <iostream>
#include <pcl/ModelCoefficients.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/visualization/cloud_viewer.h>

int
main (int argc, char** argv)
{
  pcl::PointCloud<pcl::PointXYZRGB> cloud;

  // Fill in the cloud data
  cloud.width  = 15;
  cloud.height = 10;
  cloud.points.resize (cloud.width * cloud.height);

  // Generate the data
  size_t i;
  for (i = 0; i < cloud.points.size ()/2; ++i)
    {
      // 平面におく
      cloud.points[i].x = 1024 * rand () / (RAND_MAX + 1.0);
      cloud.points[i].y = 1024 * rand () / (RAND_MAX + 1.0);
      cloud.points[i].z = 0.1 * rand () / (RAND_MAX + 1.0);
      cloud.points[i].r = 255;
      cloud.points[i].g = 255;
      cloud.points[i].b = 255;
    }

  for (; i < cloud.points.size (); ++i)
    {
      // ちらばらせる
      cloud.points[i].x = 1024 * rand () / (RAND_MAX + 1.0);
      cloud.points[i].y = 1024 * rand () / (RAND_MAX + 1.0);
      cloud.points[i].z = 1024 * rand () / (RAND_MAX + 1.0);
      cloud.points[i].r = 255;
      cloud.points[i].g = 255;
      cloud.points[i].b = 255;
    }

  // Set a few outliers
  cloud.points[0].z = 2.0;
  cloud.points[3].z = -2.0;
  cloud.points[6].z = 4.0;

  std::cerr << "Point cloud data: " << cloud.points.size () << " points" << std::endl;
  for (size_t i = 0; i < cloud.points.size (); ++i)
    std::cerr << "    " << cloud.points[i].x << " "
     << cloud.points[i].y << " "
     << cloud.points[i].z << std::endl;

  pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
  pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
  // Create the segmentation object
  pcl::SACSegmentation<pcl::PointXYZRGB> seg;
  // Optional
  seg.setOptimizeCoefficients (true);
  // Mandatory
  seg.setModelType (pcl::SACMODEL_PLANE);
  seg.setMethodType (pcl::SAC_RANSAC);
  seg.setDistanceThreshold (0.1);

  seg.setInputCloud (cloud.makeShared ());
  seg.segment (*inliers, *coefficients);

  if (inliers->indices.size () == 0)
    {
      PCL_ERROR ("Could not estimate a planar model for the given dataset.");
      return (-1);
    }

  std::cerr << "Model coefficients: " << coefficients->values[0] << " "
   << coefficients->values[1] << " "
   << coefficients->values[2] << " "
   << coefficients->values[3] << std::endl;

  std::cerr << "Model inliers: " << inliers->indices.size () << std::endl;
  for (size_t i = 0; i < inliers->indices.size (); ++i) {
    std::cerr << inliers->indices[i] << "    " << cloud.points[inliers->indices[i]].x << " "
     << cloud.points[inliers->indices[i]].y << " "
     << cloud.points[inliers->indices[i]].z << std::endl;
    cloud.points[inliers->indices[i]].r = 255;
    cloud.points[inliers->indices[i]].g = 0;
    cloud.points[inliers->indices[i]].b = 0;
  }
  pcl::visualization::CloudViewer viewer("Cloud Viewer");

  viewer.showCloud(cloud.makeShared());

  while (!viewer.wasStopped ())
    {
     
    }

  return (0);
}
するとこんな感じで平面っぽいところにあるポイントが赤く表示されました。

CMakeLists.txtはいつもと同じです。

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)

project(planar_segmentation)

find_package(PCL 1.1 REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable (planar_segmentation planar_segmentation.cpp)
target_link_libraries (planar_segmentation ${PCL_LIBRARIES})
$ cmake .
$ make
でビルドして、
$ ./planar_segmentation
で実行してみます。


SACSegmentationというClassが今回の本質のようです。ここにSACMODEL_PLANE=平面モデルを指定したり、
setDistanceThresholdでモデルとの誤差の閾値を指定しています。setMethodTypeで計算方法を選択(今回はSAC_RANSAC)しています。RANSACは確率的なモデル推定だったきがします。
coefficients->valuesに入っているのは推定されたモデル
ax+by+cz+d=0の平面の式になります。

これで平面上にあるポイントが検出できました。

さらにKinectでやってみました。前回のKinectのキャプチャサンプルに今回のを合体させてみました。
一番広い平面が真っ赤にそまります。これは楽しい!

一応ソースコードです。適当です。
#include <iostream>
#include <pcl/ModelCoefficients.h>
#include <pcl/io/openni_grabber.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/visualization/cloud_viewer.h>

void segmentate(pcl::PointCloud<pcl::PointXYZRGB>& cloud, double threshould) {
  pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
  pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
  // Create the segmentation object
  pcl::SACSegmentation<pcl::PointXYZRGB> seg;
  // Optional
  seg.setOptimizeCoefficients (true);
  // Mandatory
  seg.setModelType (pcl::SACMODEL_PLANE);
  seg.setMethodType (pcl::SAC_RANSAC);
  seg.setDistanceThreshold (threshould);

  seg.setInputCloud (cloud.makeShared ());
  seg.segment (*inliers, *coefficients);

  for (size_t i = 0; i < inliers->indices.size (); ++i) {
    cloud.points[inliers->indices[i]].r = 255;
    cloud.points[inliers->indices[i]].g = 0;
    cloud.points[inliers->indices[i]].b = 0;
  }
}

 class SimpleOpenNIViewer
 {
   public:
     SimpleOpenNIViewer () : viewer ("PCL OpenNI Viewer") {}

     void cloud_cb_ (const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &cloud)
     {
       if (!viewer.wasStopped()) {
  pcl::PointCloud<pcl::PointXYZRGB> segmented_cloud(*cloud);
  segmentate(segmented_cloud, 0.01);
         viewer.showCloud (segmented_cloud.makeShared());
       }
     }

     void run ()
     {
       pcl::Grabber* interface = new pcl::OpenNIGrabber();

       boost::function<void (const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr&)> f =
         boost::bind (&SimpleOpenNIViewer::cloud_cb_, this, _1);

       interface->registerCallback (f);
       interface->start ();
       while (!viewer.wasStopped())
       {
         sleep (1);
       }

       interface->stop ();
     }

     pcl::visualization::CloudViewer viewer;
 };

 int main ()
 {
   SimpleOpenNIViewer v;
   v.run ();
   return 0;
 }

2011年8月22日月曜日

Point Cloud Libraryを試す(その3:Kinectからデータ取得)

いよいよKinectを使ってデータを取得してみます。
http://pointclouds.org/documentation/tutorials/openni_grabber.php#openni-grabber

データが取得できれば、これまでやった、ファイルへの保存、ビューワでの表示、がとりあえずできるようになるわけです。
公式のサンプルコードは動かないので↓のように修正しました。

#include <pcl/io/openni_grabber.h>
#include <pcl/visualization/cloud_viewer.h>

 class SimpleOpenNIViewer
 {
   public:
     SimpleOpenNIViewer () : viewer ("PCL OpenNI Viewer") {}

     void cloud_cb_ (const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &cloud)
     {
       if (!viewer.wasStopped())
         viewer.showCloud (cloud);
     }

     void run ()
     {
       pcl::Grabber* interface = new pcl::OpenNIGrabber();

       boost::function<void (const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr&)> f =
         boost::bind (&SimpleOpenNIViewer::cloud_cb_, this, _1);

       interface->registerCallback (f);

       interface->start ();

       while (!viewer.wasStopped())
       {
         sleep (1);
       }

       interface->stop ();
     }

     pcl::visualization::CloudViewer viewer;
 };

 int main ()
 {
   SimpleOpenNIViewer v;
   v.run ();
   return 0;
 }

ビューワで表示されます。




さらに
#include<pcl/io/pcd_io.h>
して、cloud_cb_の中に
pcl::io::savePCDFileBinary("kinect.pcd", *cloud);
を追加すればファイルに保存もできますね。
マイフレーム保存してもけっこう軽いです。

次回は平面抽出をやります。

2011年8月21日日曜日

Point Cloud Libraryを試す(その2:ビューワ編)

前回ファイルの書き込みをしました。
今回は読み込みを飛ばして可視化をします。
可視化できないと何をやっているのかさっぱりなので。

http://pointclouds.org/documentation/tutorials/cloud_viewer.php#cloud-viewer


前回のコードを少し書き換えて、ビューワのコードをいれてみました。

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h> // 追加

int
  main (int argc, char** argv)
{
  pcl::PointCloud<pcl::PointXYZ> cloud;
  
  // Fill in the cloud data
  cloud.width    = 5;
  cloud.height   = 1;
  cloud.is_dense = false;
  cloud.points.resize (cloud.width * cloud.height);

  for (size_t i = 0; i < cloud.points.size (); ++i)
  {
    cloud.points[i].x = 1024 * rand () / (RAND_MAX + 1.0);
    cloud.points[i].y = 1024 * rand () / (RAND_MAX + 1.0);
    cloud.points[i].z = 1024 * rand () / (RAND_MAX + 1.0);
  }
  // 追加
  pcl::visualization::CloudViewer viewer ("Simple Cloud Viewer");
  viewer.showCloud (cloud.makeShared());
  while (!viewer.wasStopped ()) {
  }

  return (0);
}


CMakeLists.txtは以下のような感じ。

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)

project(pcd_write)

find_package(PCL 1.1 REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable (pcd_write pcd_write.cpp)
add_executable (pcl_view_test pcl_view_test.cpp)

target_link_libraries (pcd_write ${PCL_COMMON_LIBRARIES} ${PCL_IO_LIBRARIES})
target_link_libraries (pcl_view_test ${PCL_LIBRARIES})

$ ./pcl_view_test
とすると以下のようなビューワが立ち上がります。
マウスを駆使してうまく表示します。ホイールで縮小するとよさそうです。


見えないでしょうがちっちゃい5つの白い点が作成したポイントクラウドです。

ためしに点を100x100くらいにしてみます。widthとheightを100にしてみます。

おー、ポイントクラウドって感じですね。

公式のチュートリアルはこちらです。
もう少し詳しいので必要になったら参照したいと思います。
http://pointclouds.org/documentation/tutorials/cloud_viewer.php#cloud-viewer

2011年8月20日土曜日

Point Cloud Libraryを試す(その1:インストール&コンパイルテスト編)

ROSを使わない前提でのインストールを説明します。

(ROSでのPCLのインストールは簡単です。
$ sudo apt-get install ros-diamondback-point-cloud-perception
だけ。ROSでは/usr/とかにインストールしないので、以下のインストール方法と競合はしません。)

相変わらず環境はUbuntu 10.04です。
http://pointclouds.org/downloads/linux.html


sudo add-apt-repository ppa:v-launchpad-jochen-sprickerhof-de/pcl
sudo apt-get update
sudo apt-get install libpcl-1.1-dev

以上でおしまいです。
簡単ですね。

ではまずこれをやります。

Writing Point Cloud data to PCD files (ポイントクラウドデータをPCDファイルに書きこむ)

まず以下の内容をpcd_write.cppというファイル名で保存します。



#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>

int
  main (int argc, char** argv)
{
  pcl::PointCloud<pcl::PointXYZ> cloud;

  // Fill in the cloud data
  cloud.width    = 5;
  cloud.height   = 1;
  cloud.is_dense = false;
  cloud.points.resize (cloud.width * cloud.height);

  for (size_t i = 0; i < cloud.points.size (); ++i)
  {
    cloud.points[i].x = 1024 * rand () / (RAND_MAX + 1.0);
    cloud.points[i].y = 1024 * rand () / (RAND_MAX + 1.0);
    cloud.points[i].z = 1024 * rand () / (RAND_MAX + 1.0);
  }

  pcl::io::savePCDFileASCII ("test_pcd.pcd", cloud);
  std::cerr << "Saved " << cloud.points.size () << " data points to test_pcd.pcd." << std::endl;

  for (size_t i = 0; i < cloud.points.size (); ++i)
    std::cerr << "    " << cloud.points[i].x << " " << cloud.points[i].y << " " << cloud.points[i].z << std::endl;

  return (0);
}



で、次のようなCMakeLists.txtを作成します。


cmake_minimum_required(VERSION 2.8 FATAL_ERROR)

project(pcd_write)

find_package(PCL 1.1 REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable (pcd_write pcd_write.cpp)
target_link_libraries (pcd_write ${PCL_COMMON_LIBRARIES} ${PCL_IO_LIBRARIES})


$ cmake .
$ make
とするとpcd_writeという実行ファイルができるはずです。
$ ./pcd_write
して、以下のように表示されればOK

$ ./pcd_write
Saved 5 data points to test_pcd.pcd.
    0.352222 -0.151883 -0.106395
    -0.397406 -0.473106 0.292602
    -0.731898 0.667105 0.441304
    -0.734766 0.854581 -0.0361733
    -0.4607 -0.277468 -0.916762

test_pcd.pcdというファイルができているはずです。
中身は

# .PCD v.7 - Point Cloud Data file format
VERSION .7
FIELDS x y z
SIZE 4 4 4
TYPE F F F
COUNT 1 1 1
WIDTH 5
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 5
DATA ascii
0.35222197 -0.15188313 -0.10639524
-0.3974061 -0.47310591 0.29260206
-0.73189831 0.66710472 0.44130373
-0.73476553 0.85458088 -0.036173344
-0.46070004 -0.2774682 -0.91676188
のようになっています。

pcl::PointXYZの定義は

// \brief A point structure representing Euclidean xyz coordinates.
struct PointXYZ
{
  float x;
  float y;
  float z;
};
となっています。
たんなる3次元座標ですね。この他にも色情報を含んだPointXYZRGBなど、さまざまなタイプがpcl/point_types.hに定義されています。

pcl::PointCloudクラスはwidthやheightを持ちます。これは画像のアナロジーになっているみたいです。
Kinectでは距離画像(画素が距離情報の画像)を取れるので親和性が高いのでしょう。

is_denseはTrueの場合にNaNやInfが値として入っていないことを保証するようです。

あとstd_msgs::Header型のheaderという変数も持ちます。これはROSのものと同じ型です。
ROSに依存していないのになぜこれが使えるかというと、
/usr/include/pcl-1.1/の下にstd_msgsとsensor_msgsがインストールされているからです。
非常に気持ち悪いですね。

あとは
pcl::io::savePCDFileASCII関数でファイルに出力しています。非常に簡単ですね。

2011年8月19日金曜日

Point Cloud Libraryを試す(その0)

かなり遅くなりましたが今後このブログでPoint Cloud Library (PCL)を試したいと思います。

PCLはKinectやレーザーレンジファインダで獲得できる3次元の点群を使った認識を行うためのライブラリです。(たぶん)
(including filtering, feature estimation, surface reconstruction, registration, model fitting and segmentation)とあります。


HPを見るとスポンサーとして、intel, nvidia, willowなどが並び、日本でも産総研、東大、トヨタが付いているようですね。


私はPCLはかなり前から注目していましたが、正直何に使っていいか分かりませんでした。
Kinectが発売され、誰でも使えるようになり、さらに注目度が増していたわけですが、
やはりどうロボットにいれていいかわからず手がでませんでした。
6軸以上のアームがあれば物体認識に使えるんでしょうけど、
そんなもの持っていませんし、作るにもお金とスキルと時間が必要です。

また、なんとか私が持っているロボット(移動台車、Kinect、2軸アーム)での利用法をさがそうとしていましたが、
やはり思いつきませんでした。
(1つ考えていますが、あまり面白くないです。誰かネタがあったら教えてください。)

でも勉強していくうちに思いつくかもしれない、と思って見切り発車でやっていこうと思います。

PCLはROS依存とROS依存じゃないところをちゃんと意識して作っているっぽいので、ROSじ
ゃない方面からやるか、ROSでやるか、という2つのやり方があると思います。
ドキュメントの再利用性を考えて、ROS非依存で進めて、最後にROSからだとこうなる、という感じで進めようかと思います。
最後にルンバにKinectを載せてなんかやるでしょう。

ではでは。

2011年8月16日火曜日

OpenRTM-asit ROSパッチ(ros port)を使ってルンバを操縦する

前回OpenRTM-aistからROSを使えるようにしました。
次はお決まりですがルンバを動かします。

今回はOpenRTM-aistの仮想ジョイスティックコンポーネントを利用してルンバを動かします。

構成としては

TkJoyStick(RTC) -> JoyRTM2velROS(今回作ったコンポーネント)(RTC/ROS) -> いつもの自作ルンバノード(ROS)

という感じです。
TkJoyStickはOpenRTM-aistのサンプルに入っていて、ジョイスティックっぽいGUIです。

面倒なのでビデオ解説です。



JoyRTM2velROSのソースはTkJoyStickからの入力(TimedFloatSeq)をROSのgeometry_msgs/Twist型に変換しているだけです。
やはりOpenRTMとROSは非常に似ていますね。

OpenRTM-aistのコードの自動生成は便利だけど修正がめんどくさいです。
とくにRosPortのように標準ツールでサポートされていないと大変です。
なにかいい方法があれば教えてください。

参考程度にcppのソースファイルだけ貼りつけておきます。
いつも通り適当です。

一応リポジトリに
otl-ros-pkg/otl_nav/JoyRTM2velROS
としておいておきました。

【参考サイト】
http://code.google.com/p/rtm-ros-robotics/wiki/rosport_Example
http://code.google.com/p/rtm-ros-robotics/wiki/RTM_HelloWorldSample



ヘッダファイル

// -*- C++ -*-
/*!
 * @file  JoyRTM2velROS.h
 * @brief convert Joystick sample port to ROS twist msg
 * @date  $Date$
 *
 * $Id$
 */

#ifndef JOYRTM2VELROS_H
#define JOYRTM2VELROS_H

#include <rtm/Manager.h>
#include <rtm/DataFlowComponentBase.h>
#include <rtm/CorbaPort.h>
#include <rtm/DataInPort.h>
#include <rtm/DataOutPort.h>
#include <rtm/idl/BasicDataTypeSkel.h>
#include <rtm/idl/ExtendedDataTypesSkel.h>
#include <rtm/idl/InterfaceDataTypesSkel.h>
#include <rtm/RosOutPort.h>
#include "geometry_msgs/Twist.h"

using namespace RTC;

/*!
 * @class JoyRTM2velROS
 * @brief convert Joystick sample port to ROS twist msg
 *
 */
class JoyRTM2velROS
  : public RTC::DataFlowComponentBase
{
 public:
  /*!
   * @brief constructor
   * @param manager Maneger Object
   */
  JoyRTM2velROS(RTC::Manager* manager);

  /*!
   * @brief destructor
   */
  ~JoyRTM2velROS();

  /***
   *
   * The initialize action (on CREATED->ALIVE transition)
   * formaer rtc_init_entry() 
   *
   * @return RTC::ReturnCode_t
   * 
   * 
   */
   virtual RTC::ReturnCode_t onInitialize();

  /***
   *
   * The execution action that is invoked periodically
   * former rtc_active_do()
   *
   * @param ec_id target ExecutionContext Id
   *
   * @return RTC::ReturnCode_t
   * 
   * 
   */
   virtual RTC::ReturnCode_t onExecute(RTC::UniqueId ec_id);

 protected:

  // Configuration variable declaration
  // 
  /*!
   * 
   * - Name:  max_linear_velocity
   * - DefaultValue: 0.1
   */
  double m_max_linear_velocity;
  /*!
   * 
   * - Name:  max_angular_velocity
   * - DefaultValue: 0.2
   */
  double m_max_angular_velocity;
  // 

  // DataInPort declaration
  // 
  TimedFloatSeq m_joyInput;
  /*!
   */
  InPort m_joyInputIn;
  
  // ROS Port
  geometry_msgs::Twist m_rosVel;
  RosOutPort m_rosVelOut;

 private:

};


extern "C"
{
  DLL_EXPORT void JoyRTM2velROSInit(RTC::Manager* manager);
};

#endif // JOYRTM2VELROS_H

実体(.cpp)

// -*- C++ -*-
/*!
 * @file  JoyRTM2velROS.cpp
 * @brief convert Joystick sample port to ROS twist msg
 * @date $Date$
 *
 * $Id$
 */

#include "JoyRTM2velROS.h"

// Module specification
// <rtc-template block="module_spec">
static const char* joyrtm2velros_spec[] =
  {
    "implementation_id", "JoyRTM2velROS",
    "type_name",         "JoyRTM2velROS",
    "description",       "convert Joystick sample port to ROS twist msg",
    "version",           "1.0.0",
    "vendor",            "OTL",
    "category",          "Sample",
    "activity_type",     "PERIODIC",
    "kind",              "DataFlowComponent",
    "max_instance",      "1",
    "language",          "C++",
    "lang_type",         "compile",
    // Configuration variables
    "conf.default.max_linear_velocity", "0.2",
    "conf.default.max_angular_velocity", "0.4",
    // Widget
    "conf.__widget__.max_linear_velocity", "slider",
    "conf.__widget__.max_angular_velocity", "slider",
    // Constraints
    ""
  };
// </rtc-template>

/*!
 * @brief constructor
 * @param manager Maneger Object
 */
JoyRTM2velROS::JoyRTM2velROS(RTC::Manager* manager)
    // <rtc-template block="initializer">
  : RTC::DataFlowComponentBase(manager),
    m_joyInputIn("joy_input", m_joyInput)

    // </rtc-template>
    ,
    m_rosVelOut("cmd_vel", "rtm2ros", m_rosVel)
{
}

/*!
 * @brief destructor
 */
JoyRTM2velROS::~JoyRTM2velROS()
{
}



RTC::ReturnCode_t JoyRTM2velROS::onInitialize()
{
  // Registration: InPort/OutPort/Service
  // <rtc-template block="registration">
  // Set InPort buffers
  addInPort("joy_input", m_joyInputIn);

  // Set OutPort buffer

  // Set service provider to Ports

  // Set service consumers to Ports

  // Set CORBA Service Ports

  // </rtc-template>

  // <rtc-template block="bind_config">
  // Bind variables and configuration variable
  bindParameter("max_linear_velocity", m_max_linear_velocity, "0.2");
  bindParameter("max_angular_velocity", m_max_angular_velocity, "0.4");
  // </rtc-template>

  addRosOutPort("ros_velocity", m_rosVelOut);

  return RTC::RTC_OK;
}


RTC::ReturnCode_t JoyRTM2velROS::onExecute(RTC::UniqueId ec_id)
{
  if(m_joyInputIn.isNew()) {
    m_joyInputIn.read();

    m_rosVel.linear.x = m_joyInput.data[1] * 0.005;
    m_rosVel.angular.z = -m_joyInput.data[0] * 0.010;

    if ( m_max_linear_velocity < m_rosVel.linear.x) {
      m_rosVel.linear.x = m_max_linear_velocity;
    } else if (-m_max_linear_velocity > m_rosVel.linear.x) {
      m_rosVel.linear.x = -m_max_linear_velocity;
    } else if (fabs(m_rosVel.linear.x) < 0.01) {
      m_rosVel.linear.x = 0.0;
    }
    if ( m_max_angular_velocity < m_rosVel.angular.z) {
      m_rosVel.angular.z = m_max_angular_velocity;
    } else if (-m_max_angular_velocity > m_rosVel.angular.z) {
      m_rosVel.angular.z = -m_max_angular_velocity;
    } else if (fabs(m_rosVel.angular.z) < 0.01) {
      m_rosVel.angular.z = 0.0;
    }

    m_rosVelOut.write();
  }
  return RTC::RTC_OK;
}



extern "C"
{

  void JoyRTM2velROSInit(RTC::Manager* manager)
  {
    coil::Properties profile(joyrtm2velros_spec);
    manager->registerFactory(profile,
                             RTC::Create<JoyRTM2velROS>,
                             RTC::Delete<JoyRTM2velROS>);
  }

};

OpenRTM-asit ROSパッチを試す(インストール編)

OpenRTMにROS通信を追加するパッチがあります。
これを使ってみます。

環境はUbuntu10.04、ROSはdiamondbackです。
かなり苦労しました。

http://www.openrtm.org/OpenRTM-aist/html/E3839EE3838BE383A5E382A2E383AB2Frosport.html

ソースからOpenRTM-aistをビルドする必要ああるのでソースをゲットします。
1.0.0です。

$ wget http://www.openrtm.org/pub/OpenRTM-aist/cxx/1.0.0/OpenRTM-aist-1.0.0-RELEASE.tar.bz2

パッチもゲット
$ wget http://www.openrtm.org/pub/OpenRTM-aist/cxx/1.0.0/ros_transport.patch-1.0.1.tar.gz


aptでいれたOpenRTM-aistは削除しておきます。
$ sudo apt-get remove openrtm-aist-example openrtm-aist openrtm-aist-dev

パッケージの展開
$ tar jxvf OpenRTM-aist-1.0.0-RELEASE.tar.bz2
$ tar zxvf ros_transport.patch-1.0.1.tar.gz
$ cd OpenRTM-aist-1.0.0

パッチを当てます。

$ patch -p0 < ../ros_transport.patch

そしてautoconfができるようにlibtool.m4を現在使っているシステムのものと入れ替えます(ここ重要)
$ find . -name libtool.m4 -exec cp /usr/share/aclocal/libtool.m4 {} \;

さらにsrc/lib/rtm/Makefile.amの以下の変数を次のように書き換えます。(ここも重要)
(cturtleを使っている場合はこれなくても動くようです)

ros_cflags=`rospack export --lang=cpp --attrib=cflags roscpp`
ros_libs=`rospack export --lang=cpp --attrib=lflags roscpp`

そしたらautoreconfして、あとはお決まりの流れです。

$ autoreconf -ifv
$ ./configure
$ make

インストール
$ sudo make install 
これで/usr/local/以下にインストールされます。



@hyaguchijskさんに協力をいただきました。ありがとうございました。

次にサンプルをmakeします。
$ wget http://www.openrtm.org/pub/OpenRTM-aist/cxx/1.0.0/examples.ros-1.0.0.tar.gz
$ tar zxvf examples.ros-1.0.0.tar.gz
$ cd examples.ros
$ cd publisher
$ make

$ cd ../subscriber
$ make

この状態でpublisherCompとsubscriberCompを動かしてActivateすると
それぞれPub/Subしてくれます。

やっと動いた・・・。