ラベル Tutorial の投稿を表示しています。 すべての投稿を表示
ラベル Tutorial の投稿を表示しています。 すべての投稿を表示

2012年11月25日日曜日

rosserialを使ってArduinoとROSで通信する

みなさんArduino使っていますか?
イタリア製のいかしたマイコンです。
mbedのほうがオシャレな気がしますが、
まだまだArduinoのほうが強い気がします。

ArduinoとROSを通信させたいときに便利なrosserial_arduinoを紹介します。

rosserial_arduinoは以下のメリットがあります。

  • ArduinoのスケッチをROSライクに書ける
  • ArduinoとROSのインタフェースで通信できる

まあ、要するにマイコンとPCのプロトコルをいちいち決めるのがめんどくさいときに楽できますよ、ってことです。

ちなみにrosserialはシリアル通信でROSをおしゃべりするための汎用的なライブラリで、rosserial_arduinoは、そのArduino用ライブラリになります。

PCとはjava/pythonで接続します。


チュートリアルはこちら。

http://ros.org/wiki/rosserial_arduino/Tutorials/Arduino%20IDE%20Setup
http://ros.org/wiki/rosserial_arduino/Tutorials/Hello%20World

インストール

sudo apt-get install ros-fuerte-rosserial

でもいいんですが、これだと最新のArduino IDE(1.0以降)で動きません。
なので、最新版をソースから使うのがいいです。
(groovyではそのまま動くと思います。)


hg clone https://kforge.ros.org/rosserial/hg rosserial
rosdep install rosserial_arduino
rosmake rosserial_arduino


そしたらそれを以下のコマンドでインストールします。<sketchbook>はArduino IDEをインストールしたパスで置き換えてくださいね。


roscd rosserial_arduino/libraries
cp -r ros_lib <sketchbook>/libraries/

するとArduinoのサンプルにros_libというのが出るので、
これで遊べます。

ExampleからHelloWorldを選択して、ダウンロードしてみてください。

実行

まずroscoreを上げます。


roscore


次にマイコンとシリアル通信するPCのソフトを上げます。

rosrun rosserial_python serial_node.py /dev/ttyUSB0


するとすでにArduinoがROSをしゃべっているので、確認しましょう。
rostopic echo chatter



Publish/Subscribeができるようです。サービスはまだないのかな?

2012年11月19日月曜日

Interactive Markersを使おう(2):作って仕組みを理解する

では引き続きInteractive Markersです。

今回は簡単なサンプルを書いて、仕組みを理解しましょう。

http://www.ros.org/wiki/rviz/Tutorials/Interactive%20Markers%3A%20Writing%20a%20Simple%20Interactive%20Marker%20Server


roscreate-pkg im_tutorials roscpp interactive_markers
cd im_tutorials
以下をsrc/simple_marker.cppとして保存。


#include <ros/ros.h>

#include <interactive_markers/interactive_marker_server.h>

void processFeedback(
    const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback )
{
  ROS_INFO_STREAM( feedback->marker_name << " is now at "
      << feedback->pose.position.x << ", " << feedback->pose.position.y
      << ", " << feedback->pose.position.z );
}

int main(int argc, char** argv)
{
  ros::init(argc, argv, "simple_marker");

  // create an interactive marker server on the topic namespace simple_marker
  interactive_markers::InteractiveMarkerServer server("simple_marker");

  // create an interactive marker for our server
  visualization_msgs::InteractiveMarker int_marker;
  int_marker.header.frame_id = "/base_link";
  int_marker.name = "my_marker";
  int_marker.description = "Simple 1-DOF Control";

  // create a grey box marker
  visualization_msgs::Marker box_marker;
  box_marker.type = visualization_msgs::Marker::CUBE;
  box_marker.scale.x = 0.45;
  box_marker.scale.y = 0.45;
  box_marker.scale.z = 0.45;
  box_marker.color.r = 0.5;
  box_marker.color.g = 0.5;
  box_marker.color.b = 0.5;
  box_marker.color.a = 1.0;

  // create a non-interactive control which contains the box
  visualization_msgs::InteractiveMarkerControl box_control;
  box_control.always_visible = true;
  box_control.markers.push_back( box_marker );

  // add the control to the interactive marker
  int_marker.controls.push_back( box_control );

  // create a control which will move the box
  // this control does not contain any markers,
  // which will cause RViz to insert two arrows
  visualization_msgs::InteractiveMarkerControl rotate_control;
  rotate_control.name = "move_x";
  rotate_control.interaction_mode =
      visualization_msgs::InteractiveMarkerControl::MOVE_AXIS;

  // add the control to the interactive marker
  int_marker.controls.push_back(rotate_control);

  // add the interactive marker to our collection &
  // tell the server to call processFeedback() when feedback arrives for it
  server.insert(int_marker, &processFeedback);

  // 'commit' changes and send to all clients
  server.applyChanges();

  // start the ROS main loop
  ros::spin();
}



CMakeLists.txtに


rosbuild_add_executable(simple_marker src/simple_marker.cpp)

を追加。

で、
make
bin/simple_marker

roscore

rosrun rviz rviz

前回のチュートリアルでやった、Interactive MarkersのUpdate Topicを/simple_marker/updateにセット。
で、トップメニューのInteractを選択すると以下のように矢印が出るはず。


矢印をドラッグするとマーカーが動いて、コンソールにメッセージが出ます。

visualization_msgs::InteractiveMarkerControl::MOVE_AXISをvisualization_msgs::InteractiveMarkerControl::ROTATE_AXISに変えて、コンパイル&実行してみましょう。

矢印が輪っかに変わりました。


ここでソースをおさらいします。
やっていることは、
  • InteractiveMarkerServerを作る
  • InteractiveMarkerを作り、そこにMarker(見た目)とコントローラをセットする
  • InteractiveMarkerをInteractiveMarkerServerにコールバックと共に登録する。
コールバックにはvisualization_msgs::InteractiveMarkerFeedbackConstPtrが渡されるのでこれを使ってやりたいことを実現する。コールバックにはboost::functionが渡せるようです。

2012年11月16日金曜日

Interactive Markersを使おう(1):とりあえず動かす

ひさびさにチュートリアルをやりましょう。

今回はInteractive Markersです。

rvizはご存知の通り、基本的にビューワで、ロボットの状態を一方的に表示します。
(目的地など、一部入力も可能ですが)

Interactive Markersはrvizに、ユーザからのさまざまな入力を受け付ける機能を追加します。

こちらにチュートリアルがあるので見て行きましょう。


なにはともあれ、とにかくプログラムを実行しましょう。

まずはroscore。
roscore

で、サンプルの実行。

rosrun interactive_marker_tutorials basic_controls


で、肝心のrvizを立ち上げます。
rosrun rviz rviz



以下の画像を参考にrvizの設定をしてください。



  • fixed frameを'/base_link'に
  • 左下のAddを押してInteractive Markersを加える
  • そのトピックを'/basic_controls/update'にセット

するとメニューの'Interact'を置くと↑図のように矢印が出てきますので、さわって遊びましょう。

位置姿勢を入力するさまざまなサンプルが表示されます。



basic_controlsをC-cで落として、pongを試しましょう。


rosrun interactive_marker_tutorials pong


として、InteractiveMarkersのUpdate Topicを/pong/updateにします。

すると以下のようなピンポンゲームをrviz上で遊べてしまいます!
バーをマウスでドラッグするとピンポン玉(円柱です)が動き出します。
うまくバーで跳ね返しましょう。



2012年5月26日土曜日

rosintall&rosws入門

rosintallとrosws (ROS workspace)の仕組みについて調べてみました。

rosintallは、ソースからROSのスタックを持ってきてビルドするためのものでした。
fuerteになって、rosintallはroswsで実質置き換えられたようです。
rosintallは、
rosintall, rosws, roslocate, roscoという4つのコマンドでできているようです。

roswsはrosintallでできることは全部できる、と書いてあるので、
roswsをマスターしましょう。

もとのチュートリアルはこちら。

http://www.ros.org/doc/api/rosinstall/html/rosws_tutorial.html

1.インストール

Ubuntuの人は以下のコマンドで入れることができます。

$ sudo apt-get install python-pip
$ sudo pip install -U rosinstall

2.ワークスペースの初期化

以下のコマンドを打って、/tmp/rosws_tutorialというディレクトリをワークスペースにしてみましょう。

$ cd /tmp
$ mkdir rosws_tutorial
$ cd rosws_tutorial
$ rosws init
Writing /tmp/rosws_tutorial/.rosinstall
(Over-)Writing setup.sh, setup.bash, and setup.zsh in /tmp/rosws_tutorial

rosws init complete.

Type 'source ./setup.bash' to change into this environment.
Add that source command to the bottom of your ~/.bashrc to set it up every time you log in.

If you are not using bash please see http://www.ros.org/wiki/rosinstall/NonBashShells

すると以下のファイルができます。
$ ls -a
./  ../  .rosinstall  setup.bash  setup.sh  setup.zsh
以下のようなコマンドを打ってみると、ワークスペースがセットされました。
$ rosws info
workspace: /tmp/rosws_tutorial
ROS_ROOT: None
もし、はやまって環境変数ROS_WORKSPACEがすでにセットされてるとエラーになります。

ERROR: Ambiguous workspace: ROS_WORKSPACE=/home/ogutti/ros/otl-ros-pkg, /tmp/rosws_tutorial/.rosinstall

そのときは↓のようにしましょう。
$ unset ROS_WORKSPACE
(ROS_WORKSPACEは、rosws initで作ったsetup.bashを読み込むことでセットするもののようです。)

3.ROSディストロの情報をセット

以下のようにするとfuerteの環境がセットされるみたいです。これをやることで/opt/ros/fuerte/setup.bashを読みこまなくてよくなります。
$ rosws merge /opt/ros/fuerte/.rosinstall
     Performing actions:

     Add new elements:
  /opt/ros/fuerte/share,  /opt/ros/fuerte/share/ros,  /opt/ros/fuerte/setup.sh,  /opt/ros/fuerte/stacks

Overwriting /tmp/rosws_tutorial/.rosinstall

rosws update complete.

Do not forget to do ...
$ source /tmp/rosws_tutorial/setup.sh
... in every open terminal.
Config changed, maybe you need run rosws update to update SCM entries.


使い始めるには生成したsetup.bashを読み込みましょう。

$ source setup.bash

これで、ROS_WORKSPACE環境変数がセットされました。
確かめてみてください。

$ echo $ROS_WORKSPACE
$ roscd
すると、ここに来れますね。

4.ワークスペースの拡張

折角なのでrosrubyでも入れてもらいたいところですが、rosruby入れるとメッセージのビルドが遅くなって迷惑をかけるので、最新の私のリポジトリorz-ros-pkgでも入れましょう。

$ rosws info
workspace: /tmp/rosws_tutorial
ROS_ROOT: /opt/ros/fuerte/share/ros

 Localname                 S SCM  Version-Spec UID  (Spec) URI  (Spec) [https://...]
 ---------                 - ---- ------------ ----------- -------------------------
 orz-ros-pkg               x git  master                   github.com/OTL/orz-ros-pkg.git
 /opt/ros/fuerte/stacks                                    
 /opt/ros/fuerte/share                                     
 /opt/ros/fuerte/share/ros 

以上のように表示されたでしょうか?ちゃんとorz-ros-pkgが登録されています。

$ rosws update

すると、見事に登録されたorz-ros-pkgがインストール(ダウンロード)されました。
新しいリポジトリを加えるときは、
  1. rosws mergeでrosintallファイルを追加
  2. rosws updateでダウンロード&アップデート。
という流れみたいですね。

これで大体つかめたんじゃないでしょうか?
もっと機能は豊富なので、知りたい人は原典URLを参照ください。

まとめ

ということで今までと↓が変更点です。
ここでは試しに/tmp/rosws_tutorialでやりましたが、本番は~/rosなどでやるといいでしょう。
  • .bashrcでROS_PACKAGE_PATHを直接編集しない
  • .bashrcにROS_WORKSPACEを書かない
  • .bashrcで/opt/ros/fuerte/setup.bashを読み込まない
  • 作成したWORKSPACEのsetup.bashを読み込む

2012年1月19日木曜日

rosjavaのパラメータサーバ

(この記事は2011/01/19時点でのものです。すでに古くなっている可能性があります。ご注意ください。)

今回はrosjavaのパラメータサーバを使ってみます。
ROSは一応Pub/Sub、サービス、パラメータが3種の神器だと思うので、
これでひと通りそろったことになります。


http://ros.org/wiki/rosjava/Overview/Parameters


まずnodeからParameterTreeを作ります。
ここからparameterにアクセスします。

ParameterTree params = node.newParameterTree();

で、実際に使うには以下のようにします。rosjavaではパラメータの型ごとに関数が異なります。型が合わないと例外が投げられます。

  boolean foo = params.getBoolean("/foo");
  int bar = params.getInteger("/bar", 42 /* default value */);
  double baz = params.getDouble("/foo/baz");

  params.set("/bloop", "Hello, world!");
  String helloWorld = params.getString("/bloop");

  List<Integer> numbers = params.getList("/numbers");
  Map<String, String> strings = params.getMap("/strings");

また、パラメータの変更を監視するParameterListenerを作ることができます。


params.addParameterListener("/foo/bar", new ParameterListener() {
  @Override
  public void onNewValue(Object value) {
    ...
  }
});



以上で説明は終わりです。

前回のServiceClientのサンプルをちょっと変更してパラメータを取得するようにしてみました。

/*
 * rosjava service client sample
 */

package org.ros.tutorials.service;

import org.apache.commons.logging.Log;
import org.ros.node.Node;
import org.ros.node.NodeMain;
import org.ros.node.service.ServiceClient;
import org.ros.node.service.ServiceResponseListener;
import org.ros.exception.RemoteException;
import org.ros.service.test_ros.AddTwoInts;
import org.ros.namespace.GraphName;

// add for parameter
import org.ros.node.parameter.ParameterTree;

/*
 * @author OTL
 */
public class Client implements NodeMain {

  @Override
  public GraphName getDefaultNodeName() {
    return new GraphName("rosjava_tutorial_service/client");
  }

  @Override
  public void onStart(Node node) {
    try {
      ServiceClient<AddTwoInts.Request, AddTwoInts.Response> client =
          node.newServiceClient("/add_two_ints", "test_ros/AddTwoInts");
      Thread.sleep(100);
      AddTwoInts.Request srv = new AddTwoInts.Request();

      // add for parameter
      ParameterTree params = node.newParameterTree();
      srv.a = params.getInteger("/a", 1);
      srv.b = params.getInteger("/b", 5);
     
      client.call(srv, new ServiceResponseListener<AddTwoInts.Response>() {
            @Override
                public void onSuccess(AddTwoInts.Response res) {
              log.info("call service success! " + res.sum);
            }
            @Override
                public void onFailure(RemoteException arg) {
              log.info("call service fail");
            }
        });
    } catch (Exception e) {
      if (node != null) {
        node.getLog().fatal(e);
      } else {
        e.printStackTrace();
      }
    }
  }

  @Override
  public void onShutdown(Node node) {
  }

  @Override
  public void onShutdownComplete(Node node) {
  }
}

重要なのは以下のところです。ParameterTreeをnodeから作って、getIntegerでint型のパラメータを取得しています。
rosparam set /a 100
rosparam set /b 200
などとしてから実行するとそれらを加えた結果を返してくれます。

      ParameterTree params = node.newParameterTree();
      srv.a = params.getInteger("/a", 1);
      srv.b = params.getInteger("/b", 5);

rosjavaのサービスを試す

(この記事は2011/01/19現在のものです。rosjavaは開発が盛んなので、ここに書いてあることがすでに古くなっている可能性が高いです。1週間で劇的に変化します。ご注意ください)

これまでにrosjavaのインストール、rosjavaチュートリアル(pub/sub)の実行、
Publisher、Subscriberを見てきました。

今回からrosjavaのサービスを利用してみます。

まずはパッケージの準備です。
rosjavaはビルドシステムを作るのがめんどうなので、rosjava_tutorial_pubsubをコピーします。

roscd rosjava_core
cp -r rosjava_tutorial_pubsub rosjava_tutorial_service
次にmanifest.xmlのrosjava-pathelementを修正します。
また、test_rosパッケージのAddTwoIntsサービスを利用するので、dependに追加しておきます。

<package>
  <description brief="rosjava_tutorial_service">

    rosjava_tutorial_service

  </description>
  <author>OTL</author>
  <license>BSD</license>
  <review status="unreviewed" notes=""/>
  <url>http://ros.org/wiki/rosjava_tutorial_service</url>

  <depend package="rosjava" />
  <depend package="test_ros" />

  <export>
    <rosjava-src location="src/main/java" />
    <rosjava-pathelement location="target/" groupId="org.ros" artifactId="org.ros.rosjava.tutorials.service" version="0.0.0" built="true" />
  </export>
</package>
あとは特に変更の必要はありません。
src/main/java/org/ros/tutorials/pubsubを削除して、
src/main/java/org/ros/tutorials/service/以下にソースを書きましょう。

サービスサーバは以下のような感じ。Server.javaとして保存しましょう。

/* rosjava service server sample*/

package org.ros.tutorials.service;

import org.apache.commons.logging.Log;
import org.ros.message.MessageListener;
import org.ros.namespace.GraphName;
import org.ros.node.Node;
import org.ros.node.NodeMain;
import org.ros.node.service.ServiceServer;
import org.ros.internal.node.service.ServiceResponseBuilder;
import org.ros.service.test_ros.AddTwoInts;


public class Server implements NodeMain {

  @Override
  public GraphName getDefaultNodeName() {
    return new GraphName("rosjava_tutorial_service/server");
  }
 
  @Override
  public void onStart(Node node) {
    final Log log = node.getLog();
    ServiceServer<AddTwoInts.Request, AddTwoInts.Response>
        server = node.newServiceServer("/add_two_ints",
                                       "test_ros/AddTwoInts",
      new ServiceResponseBuilder<AddTwoInts.Request, AddTwoInts.Response>() {
        @Override
        public AddTwoInts.Response build(AddTwoInts.Request request) {
          AddTwoInts.Response res = new AddTwoInts.Response();
          res.sum = request.a + request.b;
          log.info("add " + request.a + ", " + request.b);
          return res;
        }
                                       });

  }

  @Override
  public void onShutdown(Node node) {
  }

  @Override
  public void onShutdownComplete(Node node) {
  }
}

ServiceServerの型にRequestとResponseの両方を入れないといけないところがC++と違いますね。
また、ServiceResponseBuilderというものを使ってコールバックを書くようです。
(なぜか現在org.ros.internal.node.service.ServiceResponseBuilderという、internalなところにあるクラスです)


次は呼び出す方、Client.javaです。

/* rosjava service client sample
 */

package org.ros.tutorials.service;

import com.google.common.base.Preconditions;

import org.apache.commons.logging.Log;
import org.ros.node.Node;
import org.ros.node.NodeMain;
import org.ros.namespace.GraphName;
import org.ros.node.service.ServiceClient;
import org.ros.node.service.ServiceResponseListener;
import org.ros.exception.RemoteException;
import org.ros.service.test_ros.AddTwoInts;

/*
 * @author OTL
 */
public class Client implements NodeMain {
  @Override
  public GraphName getDefaultNodeName() {
    return new GraphName("rosjava_tutorial_service/client");
  }

  @Override
  public void onStart(Node node) {
    final Log log = node.getLog();
    try {
      ServiceClient<AddTwoInts.Request, AddTwoInts.Response> client =
          node.newServiceClient("/add_two_ints", "test_ros/AddTwoInts");
      Thread.sleep(100);
      AddTwoInts.Request srv = new AddTwoInts.Request();
      srv.a = 5;
      srv.b = 1;
      client.call(srv, new ServiceResponseListener<AddTwoInts.Response>() {
            @Override
                public void onSuccess(AddTwoInts.Response res) {
              log.info("call service success! " + res.sum);
            }
            @Override
                public void onFailure(RemoteException arg) {
              log.info("call service fail");
            }
        });
    } catch (Exception e) {
      if (node != null) {
        node.getLog().fatal(e);
      } else {
        e.printStackTrace();
      }
    }
  }

  @Override
  public void onShutdown(Node node) {
  }

  @Override
  public void onShutdownComplete(Node node) {
  }
}

こちらもRequestとResponseの両方の型をいれますね。
そして、callの成否時の処理をServiceResponseListenerに書くようです。

あとは普通にmakeすればできあがりです。
実行するにはroscoreを上げて、
サーバは

rosrun rosjava_bootstrap run.py rosjava_tutorial_service org.ros.tutorials.service.Server

クライアントは
rosrun rosjava_bootstrap run.py rosjava_tutorial_service org.ros.tutorials.service.Client

のように実行します。
ちなみにサーバをテストしようとして、
rosservice call /add_two_ints 1 2
とするとエラーになります。どうやらrosservice args /add_two_intsがうまく動いていないようです。

rosserviceが使えないので、サーバだけ動作確認したい場合は
rosrun test_ros add_two_ints_client
とするといいと思います。

2012年1月16日月曜日

rosjavaのチュートリアル(Subscriber)

(この記事は2011/01/19現在のものです。rosjavaは開発が激しいため、すでにここに書いてあることは正しくない可能性が高いです。1週間で全く変わる可能性もあります。ご注意ください)

前回はrosjavaでPublisherを作りました。
今回はrosjava_tutorial_pubsubの続きで、Subscriber(Listener.java)を見て行きます。
とりあえずソース貼ります。


/*
 * Copyright (C) 2011 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.ros.tutorials.pubsub;

import org.apache.commons.logging.Log;
import org.ros.message.MessageListener;
import org.ros.namespace.GraphName;
import org.ros.node.Node;
import org.ros.node.NodeMain;
import org.ros.node.topic.Subscriber;

/**
 * This is a simple rosjava {@link Subscriber} {@link Node}. It assumes an
 * external roscore is already running.
 * 
 * @author damonkohler@google.com (Damon Kohler)
 */
public class Listener implements NodeMain {
@Override
  public GraphName getDefaultNodeName() {
    return new GraphName("rosjava_tutorial_pubsub/listener");
  }

  @Override
  public void onStart(Node node) {
    final Log log = node.getLog();
    Subscriber<org.ros.message.std_msgs.string> subscriber =
        node.newSubscriber("chatter", "std_msgs/String");
    subscriber.addMessageListener(new MessageListener<org.ros.message.std_msgs.string>() {
      @Override
      public void onNewMessage(org.ros.message.std_msgs.String message) {
        log.info("I heard: \"" + message.data + "\"");
      }
    });
  }

  @Override
  public void onShutdown(Node node) {
  }

  @Override
  public void onShutdownComplete(Node node) {
  }
}

今回重要なのは以下の2つですね。

1.まずSubscriberの作成は以下です。Publisherのときと同じで文字列で型を入れてますね。
Subscriber<org.ros.message.std_msgs.String> subscriber =
      node.newSubscriber("chatter", "std_msgs/String");

2.メッセージリスナーの登録。C++でのコールバック関数登録ですね。
関数を定義をそのまま引数に入れています。
subscriber.addMessageListener(new MessageListener<org.ros.message.std_msgs.String>() {
      @Override
      public void onNewMessage(org.ros.message.std_msgs.String message) {
        log.info("I heard: \"" + message.data + "\"");
      }
});

MessageListenerは以下のような定義です。
public interface MessageListener {
  void onNewMessage(T message);
}


ログはnode.getLog().info("hogehoge")という形式ですね。

これでPubSubができました。実行方法は過去記事を参照ください。

2012年1月15日日曜日

rosjavaのチュートリアル(Publisher)

(この記事は2011/01/19現在のものです。)


2012/07/12の記事はこちら
http://ros-robot.blogspot.jp/2012/07/rosjavatalker.html

以下は古い内容ですので上記記事を参考にしてください。


rosjavaの概要をまとめたページを見つけました。

http://ros.org/wiki/rosjava/Overview

まだ書かれていない項目も多いですが、これは必読です。
javaで書かれたroscoreがあることなどが書いて有りますね。

でもとりあえずこれを無視して、rosjava_tutorial_pubsubパッケージを見ていこうと思います。

今回はとりあえずTalker(Publisherのサンプル)を見てみます。

/*               
 * Copyright (C) 2011 Google Inc.  
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not                                                                           
 * use this file except in compliance with the License. You may obtain a copy of                                                                         
 * the License at     
 *        
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the  
 * License for the specific language governing permissions and limitations under                                                                         
 * the License.    
 */

import org.ros.concurrent.CancellableLoop;
import org.ros.namespace.GraphName;
import org.ros.node.Node;
import org.ros.node.NodeMain;
import org.ros.node.topic.Publisher;

/**
 * A simple {@link Publisher} {@link Node}.
 * 
 * @author damonkohler@google.com (Damon Kohler)
 */
public class Talker implements NodeMain {

  @Override
  public GraphName getDefaultNodeName() {
    return new GraphName("rosjava_tutorial_pubsub/talker");
  }

  @Override
  public void onStart(final Node node) {
    final Publisher<org.ros.message.std_msgs.String> publisher =
        node.newPublisher("chatter", "std_msgs/String");
    // This CancellableLoop will be canceled automatically when the Node shuts
    // down.
    node.executeCancellableLoop(new CancellableLoop() {
      private int sequenceNumber;

      @Override
      protected void setup() {
        sequenceNumber = 0;
      }

      @Override
      protected void loop() throws InterruptedException {
        org.ros.message.std_msgs.String str = new org.ros.message.std_msgs.String();
        str.data = "Hello world! " + sequenceNumber;
        publisher.publish(str);
        sequenceNumber++;
        Thread.sleep(1000);
      }
    });
  }

  @Override
  public void onShutdown(Node node) {
  }

  @Override
  public void onShutdownComplete(Node node) {
  }
}

NodeMainというインタフェースを実装しています。NodeMainは

public interface NodeMain extends NodeListener {
/**
   * @return the name of the {@link Node} that will be used if a name was not
   *         specified in the {@link Node}'s associated
   *         {@link NodeConfiguration}
   */
  GraphName getDefaultNodeName();
}

となっており、NodeListenerは以下のようになっています。

public interface NodeListener {
  void onStart(Node node);
  void onShutdown(Node node);
  void onShutdownComplete(Node node);
}
ということで、Nodeスタート時にonStartが呼ばれ、終了開始時にonShutdownが呼ばれ、終了後にonShutdownCompleteが呼ばれるようです。

まず、getDefaultNodeNameでノードのデフォルトの名前を決めています。

次に、メインとなるのはonStartです。
Publisherの作り方は↓のように書くみたいですね。

Publisher<org.ros.message.std_msgs.String> publisher = node.newPublisher("chatter", "std_msgs/String");

C++とかなり似てますね。

そしてメインループはnode.executeCancellableLoopで作っています。
C-cで止められる仕組みだと思います。
setupが1回実行され、loopが回るみたいですね。そしてC-cで止まると。

Talkerはこれでおしまい。次回はListenerです。

2012年1月13日金曜日

rosjavaのチュートリアルをビルド&実行

(この記事は2011/01/19時点でのものです。現在ちゃんと動くか分かりません。rosjavaは開発が激しくついていくことが困難です。)

前回はrosjavaのインストールをしましたが、
今回はそれについてきているチュートリアルをビルド&実行します。

http://ros.org/wiki/rosjava/Tutorials/Running%20rosjava_tutorial_pubsub

前回のチュートリアルはやっておいてくださいね。

rosjavaはまだビルドが簡単じゃないです。
rosは基本的にcmakeでコンパイルしますが、javaは普通antというビルドツールを使います。rosjavaもantを使っているようです。

では、すでにrosjava_tutorial_pubsubというパッケージがあると思うので、
とりあえずビルドしましょう。

roscd rosjava_tutorial_pubsub
rosmake

ROS触ったことがある人なら意味は分かりますよね。
パッケージでrosjavaを入れてしまっている人は削除するか、ROS_PACKAGE_PATHにソースのほうが先に来るようにしないといけませんね。

では実行しましょう。まずはいつもどおりroscoreを上げます。

roscore



で、以下のようにしてtalkerを上げましょう。

rosrun rosjava_bootstrap run.py rosjava_tutorial_pubsub org.ros.tutorials.pubsub.Talker

rostopic list
すると
/rosjava_tutorial/talker
が見えますし、rostopicでちゃんとpublishされているのが分かります。
rostopic echo /chatter
data: Hello world! 1
---
data: Hello world! 2
---
data: Hello world! 3

ではlistenerも上げましょう。
rosrun rosjava_bootstrap run.py rosjava_tutorial_pubsub org.ros.tutorials.pubsub.Listener

こんな感じで表示されますね。

2012/01/12 23:56:05 org.ros.internal.node.RosoutLogger info
情報: I heard: "Hello world! 84"
2012/01/12 23:56:06 org.ros.internal.node.RosoutLogger info
情報: I heard: "Hello world! 85"
2012/01/12 23:56:07 org.ros.internal.node.RosoutLogger info
情報: I heard: "Hello world! 86"

以上で実行できました。実行方法を含め、いままでのROSとはかなりイメージ違いますね。






2010年2月6日土曜日

自律移動ソフトを試す

だんだんやることがハードになってきて、気軽にblogかけなくなってきました。

現実逃避に自律移動ソフトで遊びました。

http://www.ros.org/wiki/pr2_simulator/Tutorials/2DNavigationStackDemoWithSimple2DesksWorld
http://www.ros.org/wiki/navigation/Tutorials/RobotSetup

まずはmakeです。

$ rosdep install pr2_2dnav_gazebo rviz
$ rosmake pr2_2dnav_gazebo rviz


結構時間かかります。

で、以下のようにしてまずシミュレータを上げます。

$ roscd pr2_2dnav_gazebo
$ export ROBOT=sim
$ roslaunch pr2-simple-fake_localization.launch

こんな感じの環境ができます。

次にロボットに指令を出すためにrvizというソフトを立ち上げます。

$ roslaunch 2dnav_pr2 rviz_move_base.launch

こんな感じで、
  • マップ(黒いところが壁)
  • ロボットの推定自己位置(ロボットがいます)
  • ロボットの自己位置候補(赤矢印)
  • レーザーレンジファインダでの観測点(緑の点)
  • 3Dスキャナによるポイントクラウド(赤や青)
が表示されます。

メニューで、2D Nav Goalというボタンを押してから、
適当な場所をドラッグ(ドラッグ開始点が目標地点、開始点と終了点を結ぶ方向が目標方向)することでロボットに目標位置姿勢を与えることができます。

赤い矢印が指定した目標位置姿勢になります。


するとシミュレータ上のロボットも動きます。

これはfake_localizationという名前から分かるように、自己位置はシミュレータから直接取得しているため、
ロボットの自己位置がシミュレーションとずれることがありません。

ちゃんと自己位置を推定させるには以下のようにします。
(一旦、gazeboもrvizも終了させてください)



$ roslaunch pr2-armless-simple-amcl.launch


$ roslaunch 2dnav_pr2 rviz_move_base.launch

するとシミュレータはさきほどと同じですが、
rviz上(ロボットの認識結果)はいきなりロボットがすごくずれた位置(0,0,0)?にいます。

2D Pose Estimateのボタンを押してから、さきほど目標位置姿勢を与えたように、
ロボットの自己位置をいれてあげましょう。
緑のレーザーが地図とずれているのでまだ自己位置がずれていますね。
これくらいは修正してほしいところです。
ではこのまま、2D Nav Goalを使ってロボットを動かしてみましょう。
なかなか収束しませんが、特徴量が少ない空間なので仕方ないかもしれませんね。


自己位置推定プログラムの良し悪しを測れそうですね。

今回はライトな内容でした。
そのうち、自律移動ソフトの中身について見ていきたいと思います。