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

2012年7月26日木曜日

android版rxconsole

みなさん、rxconsole使っていますか?
ROSのログを表示する便利ツールです。

で、Android版rxconsoleを作ってみました。

完成度の高いロボットは使うのにPCを必要としない一方で、
ちょっとした状態監視にlogを見たい、というコアな要求に答えてくれる
アプリです。

https://play.google.com/store/apps/details?id=com.ogutti.ros.android.rxconsole



まあ、sshでロボットにログインすればいいんですけど、エレガントじゃないですよね〜。

まだフィルタリング機能とか一部機能が足りないと思いますが、一応実用的なのではとおもいます。

是非使っていただきフィードバックをお願いします。

2012年7月14日土曜日

android_coreのインストール&ビルド

rosjavaの入門をすっとばして、android_coreのインストールを見てみます。

原典:http://docs.rosjava.googlecode.com/hg/android_core/html/index.html

1)ソースコードの入手

まず以下の2つが必要なのでイントールしましょう。


すでにインストールしている人はAndroid SKDを最新にアップデートしておきましょう(必須です。)

あとはroswsでインストールします。


roscd
rosws merge http://android.rosjava.googlecode.com/hg/.rosinstall
rosws update
source setup.bash

2)ビルド

android_coreが必要とするgoogleパッケージをビルドして、その後、メッセージをアップデートするためrosjava_messagesをビルドします。

roscd
cd google
./gradlew install

roscd rosjava_benchmarks
../gradlew install


roscd rosjava_messages
../gradlew install

で、最後にandroid_coreをビルド。


roscd android_core
./gradlew debug


以上です。

3)サンプルの実行

androidのエミュレータを上げた状態で、

roscd android_tutorial_pubsub
ant installd

とします。するとデバイスにインストールされるので、
アプリ一覧から選択して起動。
Mater選択画面では"New Master"を選択しましょう。
アプリ内でMasterが立ち上がるみたいです。




以上です。


以下は参考情報なので気にしないでいいです。

原典のドキュメント通りにやると
私の環境では以下のようなエラーがでました。なのでgoogleパッケージのビルドを追加。

    [javac] Compiling 40 source files to /home/ogutti/ros/android_core/android_h
oneycomb_mr2/bin/classes
    [javac] /home/ogutti/ros/android_core/android_honeycomb_mr2/src/org/ros/andr
oid/view/visualization/layer/CompressedBitmapLayer.java:40: パッケージ compressed_visualization_transport_msgs は存在しません。

(参考:http://answers.ros.org/question/32319/installing-rosjava-android_core-is-missing/

さらに以下のようなエラーがでました。なのでrosjava_benchmarksのビルドを追加。
(これはいらないはずだが・・・)


    [javac] /home/ogutti/ros/android_core/android_benchmarks/src/org/ros/android/android_benchmarks/MainActivity.java:25: シンボルを見つけられません。
    [javac] シンボル: クラス TransformBenchmark
    [javac] 場所    : org.ros.rosjava_benchmarks の パッケージ
    [javac] import org.ros.rosjava_benchmarks.TransformBenchmark;
    [javac]                                  ^
    [javac] /home/ogutti/ros/android_core/android_benchmarks/src/org/ros/android/android_benchmarks/MainActivity.java:61: シンボルを見つけられません。
    [javac] シンボル: クラス TransformBenchmark
    [javac] 場所    : org.ros.android.android_benchmarks.MainActivity の クラス
    [javac]     nodeMainExecutor.execute(new TransformBenchmark(), nodeConfiguration);


さらに:android_benchmarksで以下のようなエラーがたくさんでました。これはAndroid SDKをアップデートしました。

       [dx] UNEXPECTED TOP-LEVEL EXCEPTION:
       [dx] java.lang.IllegalArgumentException: already added: Lorg/apache/xmlrp
c/XmlRpcRequestConfig;....



さらにandroid_tutorial_hokuyoで失敗。SDKアップデート後にcleanしていなかったので、
gradlew cleanして再ビルドしたら直りました。

rosjavaのプロジェクト作成&Talker作成


今回はrosjavaを利用したプロジェクトを作ってみます。
まずはrosjavaのインストールをしておいてください。
また、rosの基本は分かった人向けの記事です。

原典
http://docs.rosjava.googlecode.com/hg/rosjava_core/html/getting_started.html

1)パッケージディレクトリの作成

まずはROS_PACKAGE_PATH以下に移動してください。
今回はrosjava_tutorial_pubsubというパッケージを作成するとします。

roscreate-pkg rosjava_tutorial_pubsub
cd rosjava_tutorial_pubsub
rm Makefile CMakeLists.txt

(rosmake/rosbuildを使わないので、manifestのdependsとかは影響ないみたいです。)

2)build.gradleを作成

以下をrosjava_tutorial_pubsub直下にbuild.gradleとして保存。


apply plugin: 'java'

// The Maven plugin is only required if your package is used as a library.
apply plugin: 'maven'

// The Application plugin and mainClassName attribute are only required if
// your package is used as a binary.
apply plugin: 'application'
mainClassName = 'org.ros.RosRun'

sourceCompatibility = 1.6
targetCompatibility = 1.6

repositories {
  mavenLocal()
  maven {
    url 'http://robotbrains.hideho.org/nexus/content/groups/ros-public'
  }
}

version = '0.0.0-SNAPSHOT'
group = 'ros.my_stack'

dependencies {
  compile 'ros.rosjava_core:rosjava:0.0.0-SNAPSHOT'
}


3)ソースの配置

mkdir -p src/main/java

ソースをsrc/main/java以下に、テストをsrc/test/java以下に配置します。

今回は以下をsrc/main/java/Talker.javaとして保存。
publisherです。


package org.ros.rosjava_tutorial_pubsub;

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

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

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

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

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

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


4)ビルド

ビルドはrosjava_coreの直下にあるgradlewを使うので、以下のようにするといいかもです。

`rosstack find rosjava_core`/gradlew installApp

5)実行

roscoreを動かした状態で、

./build/install/my_rosjava/bin/rosjava_tutorial_pubsub org.ros.rosjava_tutorial_pubsub.Talker


rostopic echo /chatter

すると、ちゃんとpublishされているのが確認できます。

今回はサンプルがそうなっているので、
org.rosというドメイン名で作ってしまいましたが、自分のパッケージを作る時は、
ドメイン名+ROSパッケージ名をつけましょう。

http://docs.rosjava.googlecode.com/hg/rosjava_core/html/best_practices.html#java-package-names

2012年7月2日月曜日

rosjavaインストール

今回はroswsを使ってrosjavaをインストールします。
すでに~/rosというworkspaceがあることを前提とします。

まだworkspaceなんて作ってないよ、という人は↓を参照ください。

rosintall&rosws入門
http://ros-robot.blogspot.jp/2012/05/rosintall.html


原文
http://docs.rosjava.googlecode.com/hg/rosjava_core/html/installing.html
http://docs.rosjava.googlecode.com/hg/rosjava_core/html/building.html

workspaceができている人は↓だけでインストール終了。
簡単ですね。

roscd
rosws merge http://rosjava.googlecode.com/hg/.rosinstall
rosws update
source setup.bash
よーし続いてビルドします。

gradleというシステムを使いますが、気せず以下のコマンドでOK。
rosmakeはサポートしないそうです。


roscd rosjava_core
./gradlew install

かなり時間がかかりますが、


BUILD SUCCESSFUL

Total time: 4 mins 28.255 secs

という感じになればOKです。

./gradlew eclipse

とするとeclipseのプロジェクトファイルを作ってくれるみたいです。

今回はここまで。

次回はサンプル作成をしてみましょう。

2012年7月1日日曜日

rosjavaの今

とある読者の方からblog通りにやったけどrosjava動かなかった。
という話を聞いたのでひさしぶりにrosjavaのドキュメント見て見ました。

そしたらちゃんとしたものができつつあるみたいです。

rosjava_coreがこちら
http://docs.rosjava.googlecode.com/hg/rosjava_core/html/index.html

android_coreがこちら
http://docs.rosjava.googlecode.com/hg/android_core/html/index.html

前はantでビルドしてたけど今はGradleというものでビルドするように変わったみたいです。
rosjava/androidで作りたいものをひとつ思いついたので、
暇を見て再チャレンジしたいと思います。

2012年2月25日土曜日

ApplicationsPlatform対応Teleopアプリを作ってみた

前々回作ったAndroid デバイスを傾けるとルンバが動くというアプリを
前回紹介したApplicationsPlatformに対応させました。
というか別アプリで登録しました。
(こっちはApplicationsPlatformに対応したロボットがないと動かないので。)

アイコンも少しやる気をだしました。

以下スクリーンショット。

App Chooserでのアプリ選択画面

センサ初期化待ち

傾けた時の画面。ドロイド君が傾くよ。
ダウンロードはこちらから。(要App Chooser)
https://market.android.com/details?id=com.ogutti.ros.android.roomba_app

前回のアプリもRoomba Controllerといいながら、

「Roombaを所有し、ROIでルンバをPCから操作するデバイス(FRISK Roomba等)を所持し、すでにROSでRoombaを操作している人で、Androidデバイスを所有している」だけが使えるRoombaコントローラでした。
(全世界推定ユーザー数15人)

もしくは
「ROSで動くロボットを所有し、Androidデバイスを所有している人」が使える
ロボットコントローラでした。
(こっちは研究者いれれば結構いるかも)


今回はApplicationsPlatformに対応したロボットを持っている人用のAndroidアプリです。Turtlebot、PR2をお持ちのあなた!是非お試しください。

使い方は以下を参照ください。
http://ros.org/wiki/otl_android_roomba_app/

まず必要なスタックのソースをダウンロード。(ROS_PACKAGE_PATH

svn checkout https://otl-ros-pkg.googlecode.com/svn/trunk/otl_android

次にあなたのロボットの.installedファイルを編集してください。Turtlebotなら、turtlebot_bringupパッケージのmock_apps/turtlebot_apps.installedだと思います。


 - display: Tilt Teleop
   app: otl_android_roomba_app/roomba


あとはApp ChooserからTilt Teleopを選択すれば使えるはずです。
.appファイルを編集すると速度とか、cmd_velのremapとかができます。

(前々回のアプリ同様、不正なURIを指定してしまうと、強制終了させる必要が有ります。ライブラリの不具合っぽいです。もしかしたら使い方の問題かもですが。)

2012年2月17日金曜日

ROS Android アプリ公開してみた

ルンバ操縦用に作ってみたrosjavaで作ったAndroidアプリをのりで公開してみました。
実用性はほとんどありません。(自己満足公開です)

https://market.android.com/details?id=com.ogutti.ros.android.roomba


最初のROS_MASTER_URIの設定間違えると強制終了するしかないようなので、
注意してください。

Willowが作ったやつが結構公開されていますね。
Android 3用が多いので、2.3でも動くというのが売りですかね・・・・。

2012年2月4日土曜日

Android + rosjava でRoombaを操作

当初の目標だったAndroidでのルンバ操作アプリが一応できました。

Androidで端末の傾きセンサの値を取得し、それを速度に変換し、rosjavaを使ってtopicとして出力します。



おまけで掃除機能のOn/Off、ドックへの合体指示も出せるようにボタンをつけました。
ただし、この機能はotl_roombaパッケージのroomba_twist_node.pyを想定しています。
システム図は↓のような感じです。
Roomba制御のためにPCを経由しています。本当はAndroidからBluetoothで直接Roombaを操作可能なので、実はこのアプリはかなり冗長です。

でもこのノードは/cmd_vel (geometry_msgs/Twist)を出力するので、制御対象がルンバだろうが、PR2だろうが、動かすことができるというメリットもあります。


シミュレータでの動作画面は↓のようになっています。
スライダで最大動作速度を変えたり、ボタンでクリーナーのOn/Off等ができます。
一番上のでかいロゴに意味はありません。


リポジトリに上げましたが、
ソースもさらしておきます。まずはルンバ操作用クラス


/**
 * @license New BSD License
 * 
 */
package com.ogutti.ros.android.roomba;

import org.ros.message.geometry_msgs.Twist;
import org.ros.message.std_msgs.Bool;

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

/**
 * class for Controlling a roomba by Twist msg
 * 
 */
public class RoombaControllerNode implements NodeMain {
 private Publisher<Twist> velPublisher;
 private Publisher<Bool> cleanPublisher;
 private Publisher<Bool> dockPublisher;

 @Override
 public void onShutdown(Node arg0) {
 }

 @Override
 public void onShutdownComplete(Node arg0) {
 }

 @Override
 public void onStart(Node node) {
  velPublisher = node.newPublisher("/cmd_vel", "geometry_msgs/Twist");
  cleanPublisher = node.newPublisher("/roomba/clean", "std_msgs/Bool");
  dockPublisher = node.newPublisher("/roomba/dock", "std_msgs/Bool");

 }

 @Override
 public GraphName getDefaultNodeName() {
  return new GraphName("roomba_controller");
 }

 /**
  * start/stop cleaning motor
  * @param isOn if true start cleaning, false stop.
  */
 public void publishClean(boolean isOn) {
  if (cleanPublisher != null) {
   Bool msg = new Bool();
   msg.data = isOn;
   cleanPublisher.publish(msg);
  }
 }

 /**
  * Publish roomba's velocity (Vx, Vtheta)
  * @param linearX twist.linear.x forward speed [m/s]
  * @param angularZ twist.angular.z rotational speed [rad/s]
  */
 public void publishVelocity(double linearX, double angularZ) {
  if (velPublisher != null) {
   Twist vel = new Twist();
   vel.linear.x = linearX;
   vel.angular.z = angularZ;
   velPublisher.publish(vel);
  }
 }

 /**
  * start docking
  */
 public void publishDock() {
  if (dockPublisher != null) {
   Bool msg = new Bool();
   msg.data = true;
   dockPublisher.publish(msg);
  }
 }
}
つぎはメインのActivityのクラス
/**
 * @license New BSD License
 */

package com.ogutti.ros.android.roomba;

import java.text.DecimalFormat;
import java.util.List;
import android.os.Bundle;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.ToggleButton;

import org.ros.address.InetAddressFactory;
import org.ros.android.MessageCallable;
import org.ros.android.RosActivity;
import org.ros.android.views.RosTextView;
import org.ros.node.NodeConfiguration;
import org.ros.node.NodeMainExecutor;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import com.ogutti.ros.android.roomba.R;
import org.ros.message.geometry_msgs.Twist;

/**
 * MainActivity of this App (roomba controller)
 * 
 */
public class MainActivity extends RosActivity implements SensorEventListener {

 private RosTextView<Twist> rosTextView;
 private SensorManager sensorManager;
 private RoombaControllerNode controllerNode;
 
 private static final double LINEAR_VELOCITY_RATE  = 0.05;
 private static final double ANGULAR_VELOCITY_RATE = 0.1;

 /**
  * 1.0 means max speed, 0.0 means stop always.
  */
 private double speedRate;

 public MainActivity() {
  super("Roomba Controller", "Roomba Controller");
  speedRate = 0.5;
 }

 @SuppressWarnings("unchecked")
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
  rosTextView = (RosTextView<Twist>) findViewById(R.id.text);
  rosTextView.setTopicName("/cmd_vel");
  rosTextView.setMessageType("geometry_msgs/Twist");
  rosTextView
    .setMessageToStringCallable(new MessageCallable<String, Twist>() {
     @Override
     public String call(Twist message) {
      DecimalFormat df = new DecimalFormat();
      df.setMaximumFractionDigits(2);

      return "vel_x:\n" + df.format(message.linear.x) + "\n"
        + "vel_theta:\n" + df.format(message.angular.z);
     }
    });
 }

 @Override
 protected void init(NodeMainExecutor nodeMainExecutor) {
  // create ROS nodes
  controllerNode = new RoombaControllerNode();
  NodeConfiguration nodeConfiguration = NodeConfiguration
    .newPublic(InetAddressFactory.newNonLoopback().getHostName());
  nodeConfiguration.setMasterUri(this.getMasterUri());
  nodeMainExecutor.execute(controllerNode, nodeConfiguration);
  nodeMainExecutor.execute(rosTextView, nodeConfiguration);

  // set callback for accelerometer
  List<Sensor> sensors = sensorManager
    .getSensorList(Sensor.TYPE_ACCELEROMETER);
  if (sensors.size() > 0) {
   Sensor accelerometer = sensors.get(0);
   sensorManager.registerListener(this, accelerometer,
     SensorManager.SENSOR_DELAY_FASTEST);
  } else {
   android.util.Log.v("MainActivity", "NOT found sensor!");
  }
  
  // set toggle button's callback
  ToggleButton tb = (ToggleButton) findViewById(R.id.toggleButton1);
  tb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
   @Override
   public void onCheckedChanged(CompoundButton buttonView,
     boolean isChecked) {
    controllerNode.publishClean(isChecked);
   }
  });

  // set seekbar callback. 
  SeekBar seekBar = (SeekBar) findViewById(R.id.seekBar1);
  final TextView tv1 = (TextView) findViewById(R.id.textView1);
  seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    tv1.setText("Speed:" + progress + "%");
    speedRate = progress * 0.01f;
   }

   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {
   }

   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {
   }
  });
  Button dockButton = (Button) findViewById(R.id.button1);
  dockButton.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(android.view.View v) {
    controllerNode.publishDock();
   }
  });

 }

 @Override
 protected void onResume() {
  super.onResume();

 }

 @Override
 protected void onStop() {
  super.onStop();
  sensorManager.unregisterListener(this);
 }

 @Override
 public void onAccuracyChanged(Sensor sensor, int accuracy) {
 }

 /**
  * callback of sensor change(accelerometer)
  */
 @Override
 public void onSensorChanged(SensorEvent event) {
  if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
   double linearX = event.values[1] * -LINEAR_VELOCITY_RATE * speedRate;
   double angularZ = event.values[0] * ANGULAR_VELOCITY_RATE * speedRate;
   if (Math.abs(linearX) < LINEAR_VELOCITY_RATE) {
    linearX = 0.0d;
   }
   if (Math.abs(angularZ) < ANGULAR_VELOCITY_RATE) {
    angularZ = 0.0d;
   }
   controllerNode.publishVelocity(linearX, angularZ);
  }
 }
}
ちょっと長いですが以上になります。
Androidアプリは作るのが結構簡単なのでチャレンジしてみてはどうでしょうか。

2012年1月21日土曜日

rosjavaをandroidで動かす(その2:カメラチュートリアル)

前回はandroid_tutorial_pubsubパッケージを試してみましたが、
今回はandroid_tutorial_cameraをやってみました。

とりあえずビデオ取りました。
android上でサンプルを実行し、PC上でimage_viewを実行して画像を表示してみました。
そんだけです。

動画はiPhoneで取りました。

2012年1月20日金曜日

rosjavaをandroidで動かす(その1)

この情報は古いので↓を参考にしてください。
http://ros-robot.blogspot.jp/2012/07/androidcore.html


==========古い情報=============

今回はrosjavaをAndroidで動かします。
ビルドするところまでやります。

例のごとくrosjavaは開発が盛んなのですでに情報が古くなっている可能性が高いことをご了承ください。

まずはソースコードを入手します。

hg clone https://android.rosjava.googlecode.com/hg/rosjava_android --insecure

AndroidSDKは↓からダウンロードできます。
http://developer.android.com/sdk/index.html

tar zxvf Downloads/android-sdk_r16-linux.tgz
などとして解凍しましょう。


さらにandroid-sdkのandroidコマンドにPATHを通します。
export PATH=$PATH:~/android-sdk-linux/tools

そしてビルドします。

roscd android_tutorial_pubsub
rosmake

そしたら、eclipseでこのandroid_tutorial_pubsubフォルダをimportします。


↓が参考になると思います。
http://ros.org/wiki/rosjava/Build/Eclipse

あとはandroid_gingerbreadパッケージもimportすればeclipse上でビルドできると思います。

注:以下Android開発環境が整っているものとして書きます。
VM等は最後に載せたサイトなどを参考に構築してください。

android_tutorial_pubsubプロジェクトを右クリックして、
Run As -> Android Applicationを選択します。

エミュレータでの実行画面を載せておきます。


上のテキストボックスにはROS_MASTER_URIを書くみたいです。
ですが、このサンプルはprivate(外と繋げない)なので有効じゃないと思います。
とりあえずこのままで。

Hello world!+数字が表示されます。

左上のアイコンがかっこいいですね!

Android開発はいろんなページがあるので、そちらで勉強しておく必要があると思います。

私はここを参考にしました。
http://thinkit.co.jp/book/2010/05/06/1536

こちらにはもっといろいろまとまっています。
http://d.hatena.ne.jp/moto_maka/20110117/1295205374


このサンプルはPrivateなので、残念ながら外からつなげることができません。

次回はソースを見て、外とつなげられるようにしてみます。

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について

rosjavaの記事をここ数日書いてきましたが、開発が激しすぎて、記事にしても
すぐ陳腐化してしまいそうなので、ちょっと削除しました。

が、注意書きを加え、最新版に対応させて、また復活させました。

まだコアライブラリの使い方も定まってなさそうなので、
基本的な文法が全く変わってしまっています。
roscppとかほとんど変化ないから、そんなものかと思っていましたが、
全然違います。

まあ、今までの記事もすでに古くなっているものも多いですから、
記事が古かったらごめんなさい。ということで。。。

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とはかなりイメージ違いますね。






2012年1月12日木曜日

rosjavaインストール

この記事は古いので、rosjavaをインストールしたい方はこちらの記事を参考にしてください。
http://ros-robot.blogspot.jp/2012/07/rosjava_02.html


=== 以下古い記事 ===

思い立ってrosjavaをやることにしました。
javaはさっぱり分かりませんが、勉強します。
(javaの勉強をした人は@makingさんおすすめの本を読みましょう。
http://blog.ik.am/entry/view/id/61/title/

とりあえずAndroid(嫁ケータイ)からROSを直接しゃべるのを目標にしたいと思います。
いちおう簡単なAndroidアプリは作ってみました。
(Androidもマーケットに出すには数千円かかるんですね・・・。)

では本題です。

まずはインストールです。
以下を参考にします。

http://ros.org/wiki/rosjava/Tutorials/Install

このチュートリアルによると、rosjavaは開発が盛んだからソースから入れてね。
って書いて有ります。electricにもrosjavaパッケージはありますが、やはりソースから入れましょう。
ベースとなるROSとしてunstableかelectricのインストールが必須です。
私はelectricでやります。

環境変数ROS_PACKAGE_PATHが通った場所で以下のようにします。


hg clone https://code.googlecode.com/p/rosjava rosjava_core

するとrosjava_coreスタックができます。hgコマンドがない、というひとはmercurialを入れましょう。

一応これでインストールはOKです。

makeとかビルドするパッケージでrosmakeでやるので必要ありません。