Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introducing robot-init function #175

Open
2 of 8 tasks
garaemon opened this issue Sep 17, 2015 · 18 comments
Open
2 of 8 tasks

Introducing robot-init function #175

garaemon opened this issue Sep 17, 2015 · 18 comments

Comments

@garaemon
Copy link
Member

robot-init関数を導入したい。

解決したい問題は

  1. 複数のロボットで動くプログラムを書くときに、pr2-inithrp2jsk-initのような関数を書くのが面倒
  2. さらっとプログラムを書くときに(load "package://hrpsys_ros_bridge_tutorials/euslisp/hrp2jsk-interface.l)"と書くのが結構面倒
  3. パラメータを変えるだけで対象ロボットが変わるプログラムを書きたい

解決する方法はrobot-init (robot-name)という関数を導入する.
ロボットの定義がどのファイルに書いてあるかは仕方ないので手書きしておく(robot-interface-file)。

(defun robot-init (&optional (robot-name (ros::get-param "/robot/type")))
  (require (robot-interface-file robot-name))
  (let ((klass (read-from-string (format nil "~A-interface" robot-name))))
    (if (and (boundp klass) (subclassp (eval klass) robot-interface))
        (setq *ri* (instance* (eval klass) :init args))))
  (setq *robot* (make-robot-model-from-name robot-name))
  *ri*)

(defun robot-interface-file (name)
  "You can get robot-interface file according to `name' argument.
You can create `*ri*' like 
(progn (load (robot-file (ros::get-param \"/robot/type\")))
       (init-robot-from-name (ros::get-param \"/robot/type\")))
"
  (let ((lower-name (string-downcase name)))
    (cond
     ((string= lower-name "pr2")
      "package://pr2eus/pr2-interface.l")
     ((string= lower-name "hrp2jsk")
      "package://hrpsys_ros_bridge_tutorials/euslisp/hrp2jsk-interface.l")
     ((string= lower-name "hrp2jsknt")
      "package://hrpsys_ros_bridge_tutorials/euslisp/hrp2jsknt-interface.l")
     ((string= lower-name "hrp2jsknts")
      "package://hrpsys_ros_bridge_tutorials/euslisp/hrp2jsknts-interface.l")
     ((string= lower-name "staro")
      "package://hrpsys_ros_bridge_tutorials/euslisp/staro-interface.l")
     ((string= lower-name "jaxon")
      "package://hrpsys_ros_bridge_tutorials/euslisp/jaxon-interface.l")
     ((string= lower-name "jaxon_red")
      "package://hrpsys_ros_bridge_tutorials/euslisp/jaxon_red-interface.l")
     ((string= lower-name "urataleg")
      "package://hrpsys_ros_bridge_tutorials/euslisp/urataleg-interface.l")
     ((string= lower-name "samplerobot")
      "package://hrpsys_ros_bridge_tutorials/euslisp/samplerobot-interface.l")
     ((string= lower-name "hrp2w")
      "package://hrpsys_ros_bridge_tutorials/euslisp/hrp2w-interface.l")
     ((string= lower-name "pepper")
      "package://peppereus/pepper-interface.l")
     ((string= lower-name "nao")
      "package://naoeus/euslisp/nao-interface.l")
     (t (error "uknown robot ~A" name))
     )))

移行について

2段階で移行する。

  1. hogehoge-initrobot-initを利用するように書き換えて、warningを出す
  2. hogehoge-initを消す

hogehoge-init ➡️ robot-initの変換のためのsedスクリプトみたいなものは用意したい。

手順

議論ポイント

  • どこに定義するのか?

    robot-interface.lが良いきがする。ちょっと依存関係はおかしいかも.

    ➡️ robot-interface.l

  • 本当にファイルを書き下さなくてはいけないのか

    package.xmlにうまいことexportタグで書くという技がある気がしてきた

    ➡️ rospack plugins作戦

  • 移行をどうするか

@snozawa
Copy link
Contributor

snozawa commented Sep 17, 2015

どこに定義するのか?

robot-interface.lに一票です。
この関数を定義するとしたら、のもっともupstream寄りなところはどこかと考えると、robot-interface.lな気がします。
(apt-getでインストールした環境で、robot-initのどれか一つ(端的にはpr2)が動く最小構成をかんがえると、pr2eusがはいればよい、という意味)

本当にファイルを書き下さなくてはいけないのか

難しいですね。
これで良い気はしますが、なにか案ありますか?
同じパッケージのものは

     ((member lower-name (list "samplerobot" "jaxon" "hrp2jsk" ....) :test #'equal)
       (format nil "package://hrpsys_ros_bridge_tutorials/euslisp/~A-interface.l" lower-name))
     ((member lower-name (list "nao" "papper" "baxter" ....) :test #'equal)
       (format nil "package://~Aeus/euslisp/~A-interface.l" lower-name lower-name))

でまとめておく、というのもなきにしもあらずなきがします。

@garaemon
Copy link
Member Author

難しいですね。
これで良い気はしますが、なにか案ありますか?
同じパッケージのものは

nodeletは各パッケージ(子供パッケージ)のpackage.xmlに

  <export>
    <nodelet plugin="${prefix}/jsk_pcl_nodelets.xml"/>
  </export>

とかくと、親パッケージ(=nodelet)からその一覧を取得しています。
この作戦が利用できる気がしてきています。

$ rospack plugins --attrib=plugin nodelet
laser_proc /opt/ros/hydro/share/laser_proc/nodelets.xml
velodyne_driver /opt/ros/hydro/share/velodyne_driver/nodelet_velodyne.xml
yocs_velocity_smoother /opt/ros/hydro/share/yocs_velocity_smoother/plugins/nodelets.xml
jsk_perception /home/lueda/ros/hydro/src/jsk-ros-pkg/jsk_recognition/jsk_perception/jsk_perception_nodelets.xml
image_rotate /home/lueda/ros/hydro/src/image_pipeline/image_rotate/nodelet_plugins.xml
stereo_image_proc /home/lueda/ros/hydro/src/image_pipeline/stereo_image_proc/nodelet_plugins.xml
depth_image_proc /home/lueda/ros/hydro/src/image_pipeline/depth_image_proc/nodelet_plugins.xml
kobuki_bumper2pc /opt/ros/hydro/share/kobuki_bumper2pc/plugins/nodelet_plugins.xml
kobuki_safety_controller /opt/ros/hydro/share/kobuki_safety_controller/plugins/nodelet_plugins.xml
naoqi_sensors /home/lueda/ros/hydro/src/ros_naoqi/naoqi_bridge/naoqi_sensors/naoqicamera_nodelet.xml
velodyne_pointcloud /opt/ros/hydro/share/velodyne_pointcloud/nodelets.xml
pointcloud_to_laserscan /home/lueda/ros/hydro/src/perception_pcl/pointcloud_to_laserscan/nodelets.xml
openni2_camera /opt/ros/hydro/share/openni2_camera/openni2_nodelets.xml
resized_image_transport /home/lueda/ros/hydro/src/jsk-ros-pkg/jsk_recognition/resized_image_transport/nodelet.xml
image_proc /home/lueda/ros/hydro/src/image_pipeline/image_proc/nodelet_plugins.xml
uvc_camera /opt/ros/hydro/share/uvc_camera/nodelet_uvc_camera.xml
openni_camera /opt/ros/hydro/share/openni_camera/openni_nodelets.xml
yocs_cmd_vel_mux /opt/ros/hydro/share/yocs_cmd_vel_mux/plugins/nodelets.xml
pcl_ros /home/lueda/ros/hydro/src/perception_pcl/pcl_ros/pcl_nodelets.xml
prosilica_camera /home/lueda/ros/hydro/src/prosilica_driver/prosilica_camera/plugins/nodelet_plugins.xml
jsk_topic_tools /home/lueda/ros/hydro/src/jsk-ros-pkg/jsk_common/jsk_topic_tools/jsk_topic_tools_nodelet.xml
jsk_pcl_ros /home/lueda/ros/hydro/src/jsk-ros-pkg/jsk_recognition/jsk_pcl_ros/jsk_pcl_nodelets.xml
image_view /home/lueda/ros/hydro/src/image_pipeline/image_view/nodelet_plugins.xml
nodelet_tutorial_math /opt/ros/hydro/share/nodelet_tutorial_math/nodelet_math.xml
imagesift /home/lueda/ros/hydro/src/jsk-ros-pkg/jsk_recognition/imagesift/nodelet.xml

@garaemon
Copy link
Member Author

ためしに、pr2eus/package.xmlに以下のような内容を記述

  <export>
    <roseus name="pr2" file="${prefix}/pr2-interface.l" />
  </export>

ついでにpeppereusにも追記。

  <export>
    <roseus name="pepper" file="${prefix}/pepper-interface.l" />
  </export>

rospack pluginsで取得してみる

$ rospack plugins --attrib=name roseus
peppereus pepper
pr2eus pr2
$ rospack plugins --attrib=file roseus
peppereus /home/lueda/ros/hydro/src/jsk-ros-pkg/jsk_robot/jsk_pepper_robot/peppereus/pepper-interface.l
pr2eus /home/lueda/ros/hydro/src/jsk-ros-pkg/jsk_pr2eus/pr2eus/pr2-interface.l

@garaemon
Copy link
Member Author

つまり作戦としては、

  • package.xmlのexport部分に名前 ↔️ interfaceファイルの対応を書く
  • robot-initの中でrospack pluginsを読んで実行時に対応関係を知る(fileとnameで二回呼ばないといけないのがちょっとダサイ)

というのでどうでしょうか。

@snozawa
Copy link
Contributor

snozawa commented Sep 17, 2015

rospack pluginsは使ったことないのですが、
hrpsys_ros_bridge_tutorialsみたいに複数ロボットが同じパッケージにいる場合は並べてかくだけでOK?

書かなくてはいけないコードは減ってなくて、かつ覚えなければいけないことが増えてるようなきがちょっとだけします。

@garaemon
Copy link
Member Author

rospack pluginsは使ったことないのですが、
hrpsys_ros_bridge_tutorialsみたいに複数ロボットが同じパッケージにいる場合は並べてかくだけでOK?

はい、並べて書くだけでOKです。

書かなくてはいけないコードは減ってなくて、かつ覚えなければいけないことが増えてるようなきがちょっとだけします。

考えられる作戦は

  1. すべてを書き下しておく
  2. 何かしらかの方法だ対応付けをどこかにそれぞれ書き下す

の2つしかないと思っていて、2を採用した場合はrospack pluginsを使わないとしても、何かしら似たようなことをしなくてはいけないと思います。

覚えなければいけないこと対策としては、robot-initのエラーで丁寧に"package.xmlにこれこれかかれていないんじゃない?"ということを出すというので対応できないですかね。

@snozawa
Copy link
Contributor

snozawa commented Sep 17, 2015

  1. 何かしらかの方法だ対応付けをどこかにそれぞれ書き下す

でrospack pluginsを使うとすると、

  1. すべてを書き下しておく

で書き下す方式から書いてあるファイルが変わるだけで、
書く分量は減らず、(これ関係で)管理するファイルが増えるだけではないかな?
例えばrospack pluginsでしかできないようなメリットがあるといいんだけど。。。

@snozawa
Copy link
Contributor

snozawa commented Sep 17, 2015

  1. 何かしらかの方法だ対応付けをどこかにそれぞれ書き下す

でしかできないメリットをかんがえてみたところ、
どうしてもrobot-initの中にかくことができないものがある場合は、
rospack pluginsなどでやる必要がありそう。

例えば、クローズドなロボットを使っていてrobot-initの中にかくPRが送れないとなったときに、
クローズドなロボットのpackage.xmlにかいてさえいれば
robot-initを前提にした全てのプログラムをそのまま使える、
というのはメリットになりそう。

と考えると

  1. 何かしらかの方法だ対応付けをどこかにそれぞれ書き下す

にした方が良いですね。

@garaemon
Copy link
Member Author

で書き下す方式から書いてあるファイルが変わるだけで、
書く分量は減らず、(これ関係で)管理するファイルが増えるだけではないかな?

それはそうですね。
良い点としては、

  1. 依存関係が綺麗。なぜか親パッケージが子供のパッケージの知識を全て知っているみたいなことがなくなる
  2. rospack plugins系の作戦のなかではrospackのAPIを使えるので実装は楽(http://docs.ros.org/jade/api/rospack/html/classrospack_1_1Rosstackage.html#a93f3aef56fc3f97a9a9ee422ad7f84c9)
  3. 徐々に移行する、みたいなことができる? (根拠は直感)

@snozawa
Copy link
Contributor

snozawa commented Sep 17, 2015

rospack pluginsでパッケージを明示的に師弟するだけにして、_load-path_とかを駆使したら
rospack pluginsの呼び出しが1回+同じパッケージでロボットが増えてももうpackage.xmlをいじらなくすむ、
になったりして。

@garaemon
Copy link
Member Author

rospack pluginsでパッケージを明示的に師弟するだけにして、load-pathとかを駆使したら
rospack pluginsの呼び出しが1回+同じパッケージでロボットが増えてももうpackage.xmlをいじらなくすむ、

rospack pluginsの呼び出し回数はそこまできにしなくて良いと思います。

また、暗黙的なルールを導入すると書く分量はへって玄人的には使いやすくなると思うのですが、例えばxx-interface.lというファイルが必ずpackage/euslispの下にあるとか、それよりは明示的に書いたほうが良いかなと個人的には思います。(この例だとファイルシステムをスキャンするので重そう)

@snozawa
Copy link
Contributor

snozawa commented Sep 17, 2015

また、暗黙的なルールを導入すると書く分量はへって玄人的には使いやすくなると思うのですが、例えばxx-interface.lというファイルが必ずpackage/euslispの下にあるとか、それよりは明示的に書いたほうが良いかなと個人的には思います。(この例だとファイルシステムをスキャンするので重そう)

確かにそうですね。

@garaemon
Copy link
Member Author

https://github.com/jsk-ros-pkg/jsk_roseus/pull/369/commits
を使って、

1.irteusgl$ (pprint (ros::rospack-plugins "pr2eus" "robot-name"))
(("hrpsys_ros_bridge_tutorials" . "hrp2jsk")
 ("hrpsys_ros_bridge_tutorials" . "hrp2jsknt")
 ("hrpsys_ros_bridge_tutorials" . "hrp2jsknts")
 ("hrpsys_ros_bridge_tutorials" . "jaxon")
 ("hrpsys_ros_bridge_tutorials" . "jaxon_red")
 ("pr2eus" . "pr2"))
nil
2.irteusgl$ (pprint (ros::rospack-plugins "pr2eus" "interface-file"))
(("hrpsys_ros_bridge_tutorials"
  . "/home/lueda/ros/hydro/src/rtm-ros-robotics/rtmros_tutorials/hrpsys_ros_bridge_tutorials/euslisp/hrp2jsk-interface.l")
 ("hrpsys_ros_bridge_tutorials"
  . "/home/lueda/ros/hydro/src/rtm-ros-robotics/rtmros_tutorials/hrpsys_ros_bridge_tutorials/euslisp/hrp2jsknt-interface.l")
 ("hrpsys_ros_bridge_tutorials"
  . "/home/lueda/ros/hydro/src/rtm-ros-robotics/rtmros_tutorials/hrpsys_ros_bridge_tutorials/euslisp/hrp2jsknts-interface.l")
 ("hrpsys_ros_bridge_tutorials"
  . "/home/lueda/ros/hydro/src/rtm-ros-robotics/rtmros_tutorials/hrpsys_ros_bridge_tutorials/euslisp/jaxon-interface.l")
 ("hrpsys_ros_bridge_tutorials"
  . "/home/lueda/ros/hydro/src/rtm-ros-robotics/rtmros_tutorials/hrpsys_ros_bridge_tutorials/euslisp/jaxon_red-interface.l")
 ("pr2eus"
  . "/home/lueda/ros/hydro/src/jsk-ros-pkg/jsk_pr2eus/pr2eus/pr2-interface.l"))
nil

追加したのは
pr2eus/package.xml

+  <export>
+    <pr2eus robot-name="pr2" interface-file="${prefix}/pr2-interface.l" />
+  </export>

hrpsys_ros_bridge_tutorials/package.xml

   <export>
+    <pr2eus robot-name="hrp2jsk" interface-file="${prefix}/euslisp/hrp2jsk-interface.l" />
+    <pr2eus robot-name="hrp2jsknt" interface-file="${prefix}/euslisp/hrp2jsknt-interface.l" />
+    <pr2eus robot-name="hrp2jsknts" interface-file="${prefix}/euslisp/hrp2jsknts-interface.l" />
+    <pr2eus robot-name="jaxon" interface-file="${prefix}/euslisp/jaxon-interface.l" />
+    <pr2eus robot-name="jaxon_red" interface-file="${prefix}/euslisp/jaxon_red-interface.l" />
   </export>
(defun robot-name-interface-file ()
  (mapcar #'(lambda (robot-name robot-file)
              (cons (cdr robot-name) (cdr robot-file)))
          (ros::rospack-plugins "pr2eus" "robot-name")
          (ros::rospack-plugins "pr2eus" "interface-file"))
  )
(pprint (robot-name-interface-file))
(("hrp2jsk"
  . "/home/lueda/ros/hydro/src/rtm-ros-robotics/rtmros_tutorials/hrpsys_ros_bridge_tutorials/euslisp/hrp2jsk-interface.l")
 ("hrp2jsknt"
  . "/home/lueda/ros/hydro/src/rtm-ros-robotics/rtmros_tutorials/hrpsys_ros_bridge_tutorials/euslisp/hrp2jsknt-interface.l")
 ("hrp2jsknts"
  . "/home/lueda/ros/hydro/src/rtm-ros-robotics/rtmros_tutorials/hrpsys_ros_bridge_tutorials/euslisp/hrp2jsknts-interface.l")
 ("jaxon"
  . "/home/lueda/ros/hydro/src/rtm-ros-robotics/rtmros_tutorials/hrpsys_ros_bridge_tutorials/euslisp/jaxon-interface.l")
 ("jaxon_red"
  . "/home/lueda/ros/hydro/src/rtm-ros-robotics/rtmros_tutorials/hrpsys_ros_bridge_tutorials/euslisp/jaxon_red-interface.l")
 ("pr2"
  . "/home/lueda/ros/hydro/src/jsk-ros-pkg/jsk_pr2eus/pr2eus/pr2-interface.l"))

@snozawa
Copy link
Contributor

snozawa commented Sep 18, 2015

よさそうですね。

@snozawa
Copy link
Contributor

snozawa commented Apr 25, 2016

I'll create PR for this.

@pazeshun
Copy link
Collaborator

これの現状を整理すると、 #222 によって、

解決したい問題は

1. 複数のロボットで動くプログラムを書くときに、`pr2-init`や`hrp2jsk-init`のような関数を書くのが面倒

2. さらっとプログラムを書くときに`(load "package://hrpsys_ros_bridge_tutorials/euslisp/hrp2jsk-interface.l)"`と書くのが結構面倒

3. パラメータを変えるだけで対象ロボットが変わるプログラムを書きたい

のうち、3は解決されてそうな感じです。

1は3と同じような意味だと思っていますが、もし各ロボット用のinit関数をなくすことを目指していたとすると、#222 でも結局、pr2-interface.lなどの各interfaceファイルにpr2-initなどのinit関数が書かれていないといけないので、1はあまり解決してなさそうです。

#222 でも、(load "package://pr2eus/robot-interface.l)が必要なので、2は改善されたが完全解決はなされずといったところでしょうか。

@pazeshun
Copy link
Collaborator

#222 (comment) のように、 #222 が使われないんじゃないかという懸念があり、 #224 は一旦 #222 をrevertするものでした。
しかし、#222 がmergeされてから二年以上が経過し、 #222 にはテストコードも入っています。
#224 はcloseしてよいと思います。

また、問題3を解決する便利な方法だと思うので、今はキツいですが、僕も使っていきたいです。
今使われていないとしても、少しずつ広めていくしかないと思います。

@pazeshun
Copy link
Collaborator

すみません、robotのインスタンスが、*pr2*とか*baxter*のように、ロボット固有の名前になっているのを忘れていました。
robot-initを本格的に運用するには、全てのinit関数で

(setq *robot* *pr2*)

のように、*robot*も定義してあげるとよいのかもしれません。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants