LoginSignup
8
2

roslaunchのコードAPIを使う part2

Last updated at Posted at 2017-12-22

Day9の記事を受けて。
https://qiita.com/Nasupl_r/items/a1449cf192c57f03ffa5

「Q. roslaunchをPythonから叩きたいやつおるか?w」

A. ここにおるでw

場面によっては使えるツールだと思います

例えばテキトーにwrapして…


import roslaunch
import os

class SimpleRosLaunch(object):
    def __init__(self, ):
        self.launchfile = ""
        self.reinitialize()

    def __del__(self,):
        self.stop()

    def load_file(self, launchfile):
        if self.is_alive():
            raise RuntimeError("you need to stop before you load another launch file")
        self.launchfile = os.path.abspath(os.path.expanduser(launchfile))
        self.launch.parent.config = roslaunch.config.load_config_default([self.launchfile], None)

    def start(self,):
        local_machine = roslaunch.core.local_machine()
        for n in self.launch.parent.config.nodes:
            n.machine = local_machine
        self.launch.start()

    def is_alive(self,):
        if self.launch.parent.pm is not None and self.launch.parent.pm.is_alive() and len(self.launch.parent.pm.get_active_names())>0:
            return True
        return False

    def current_file(self, ):
        return self.launchfile

    def reinitialize(self, ):
        self.launch = roslaunch.scriptapi.ROSLaunch()

    def stop(self,):
        self.launch.stop()
        self.reinitialize()
        self.load_file(self.launchfile)

こうしてやると…

import os
import roslaunch
import rospkg
from simple_roslaunch import SimpleRosLaunch

# 初期化
simple_roslaunch = SimpleRosLaunch()
# signalをいい感じに処理する
roslaunch.pmon._sig_initialized = True
rospy.on_shutdown(simple_roslaunch.stop)
launchfile = os.path.join(rospkg.RosPack().get_path('sample_pkg'), 'launch', 'sample.launch')

simple_roslaunch.load_file(launchfile)


# スタート
def start():
    if simple_roslaunch.is_alive():
        rospy.logerr("you've already executed launch file")
        return False
    simple_roslaunch.start()
    return True

# ストップ
def stop():
    if not simple_roslaunch.is_alive():
        rospy.logerr("no launch file is launched")
        return False
    simple_roslaunch.stop()
    return True

start()stop()で起動したり止めたりできます

なにが嬉しいかというと、
例えばOccupancyGrid(/map)を保存したい時に、

<launch>
    <node pkg="map_server" type="map_saver" name="map_saver">
    </node>
</launch>

のようなlaunch fileを準備しておき、

from map_msgs.msg import SaveMap

def run_map_saver(self, req):
    global simple_roslaunch
    try:
        for n in simple_roslaunch.launch.parent.config.nodes:
            if (n.package == "map_server" and n.type == "map_saver"):
                # <node>のargsが変更できる
                n.args = unicode('-f %s'%(req.filename.data, ))
        # rosparamも変更できる
        # simple_roslaunch.launch.parent.config.params['/hoge/fuga/piyo'].value = '...'
        simple_roslaunch.start()
        while not rospy.is_shutdown():
            rospy.loginfo('saving map...')
            if not simple_roslaunch.is_alive():
                rospy.loginfo('map saved!')
                break
            rospy.sleep(0.2)
        simple_launch.stop()
    except Exception as e:
        rospy.logerr(e)

sample_service = rospy.Service('~sample_service', SaveMap, run_map_saver)

このようにlaunch fileに定義された引数などを動的に変更できます
mapに何か後処理を加えて保存したい場合もlaunch fileに後処理ノードを加えて、<remap>でmap_saverとtopicを繋げばよい、ということになります

当然ながらlaunch fileをわざわざ準備する必要もなくて

launch = roslaunch.scriptapi.ROSLaunch()
node = roslaunch.core.Node('map_server', 'map_saver')
node.args = unicode('-f %s'%(req.filename.data, ))
# namespaceも変更できる
# node.namespace = '/hogefuga'
launch.start()
launch.launch(node)
while not rospy.is_shutdown():
    rospy.loginfo("saving map...")
    if len(launch.parent.pm.get_active_names()) == 0:
        rospy.loginfo("map saved!")
        break
    rospy.sleep(0.2)
launch.stop()
del launch

その場でプロセスが起動できちゃう!プロセス管理はroslaunchにお任せ!(?)

まとめ

roslaunch APIは very unstableです
なるべく使わないようにしましょう

8
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2