jsk-ros-pkg / jsk_pr2eus

PR2 euslisp packages
https://github.com/jsk-ros-pkg/jsk_pr2eus
4 stars 41 forks source link

Introducing `robot-init` function #175

Open garaemon opened 9 years ago

garaemon commented 9 years ago

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 :arrow_right: robot-initの変換のためのsedスクリプトみたいなものは用意したい。

手順

snozawa commented 9 years ago

どこに定義するのか?

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 commented 9 years ago

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

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 commented 9 years ago

ためしに、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 commented 9 years ago

つまり作戦としては、

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

snozawa commented 9 years ago

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

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

garaemon commented 9 years ago

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

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

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

考えられる作戦は

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

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

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

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

でrospack pluginsを使うとすると、

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

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

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

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

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

と考えると

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

にした方が良いですね。

garaemon commented 9 years ago

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

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

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

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

garaemon commented 9 years ago

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

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

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

snozawa commented 9 years ago

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

確かにそうですね。

garaemon commented 9 years ago

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 commented 9 years ago

よさそうですね。

snozawa commented 8 years ago

I'll create PR for this.

pazeshun commented 5 years ago

これの現状を整理すると、 #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 commented 5 years ago

https://github.com/jsk-ros-pkg/jsk_pr2eus/pull/222#issuecomment-214929078 のように、 #222 が使われないんじゃないかという懸念があり、 #224 は一旦 #222 をrevertするものでした。 しかし、#222 がmergeされてから二年以上が経過し、 #222 にはテストコードも入っています。

224 はcloseしてよいと思います。

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

pazeshun commented 5 years ago

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

(setq *robot* *pr2*)

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