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でやるので必要ありません。