External Process Handler

external_process_handler is a package for clients to run their own tasks into Seirios.

How to setup your tasks with External Process Handler

This guide shows you how to integrate your own programs as a plugin into Seirios using external_process_handlerpackage.

1. Install movel_seirios_message

Check your Ubuntu + ROS version.

  • For Ubuntu 20.04, ROS Noetic users:

Go here to download the .deb package: https://drive.google.com/drive/folders/1hpi5NaSkFyr6QVXs83taxeHjWLulw8SH

Move the .deb into your home folder. Open a terminal window, run the command sudo apt install ./ros-noetic-movel-seirios-msgs_0.0.0-0focalXXX64.deb to install.

  • Else:

Git clone this repo here: https://gitlab.com/movelai_public/movel_seirios_msgs/-/tree/master/srv into catkin_ws/src. Then go back to /catkin_ws to run catkin_make.

2. Integration with Seirios

You need to mount your own packages/nodes as a plugin to task_supervisor for Seirios to run it.

File to modify: ../config/task_supervisor/config/task_supervisor.yaml

Look for the plugins section in the config to add your own plugin. You can give any name and type. For type, give a number not used by previous plugins.

plugins:
  - {name: detecting, type: 10, class: 'external_process_handler::ExternalProcessHandler'}

Then at the end of the file, create a new section with the same name you give for your plugin e.g. detecting. Then paste in the parameters.

detecting:
  watchdog_rate: 2.0
  watchdog_timeout: 0
  service_req: true
  launch_req: false
  service_start: "/external_process/trigger_detecting" #required if service_req is true
  service_start_msg: "" #optional  if there is any particular msg needs to sent or else empty string 
  service_stop: "/external_process/stop_detecting" #required if service_req is true
  service_stop_msg: "" #optional  if there is any particular msg needs to sent or else empty string 
  #launch_package: "yocs_velocity_smoother" #required if launch_req is true
  #launch_file: "standalone.launch"  #required if launch_req is true
  #launch_nodes: "/nodelet_manager /velocity_smoother" #required if launch_req is true
  topic_cancel_req: true
  topic_process_cancel: "external_process/cancel_publish"

3. Launching your nodes with Seirios

There are different ways to launch your own codes. Choose one in the below subsection that best suits you.

3.1. Launch with your own code

Start & stop

You need to write a ROS service service_start with start_handler as the callback function to start your code.

And you need another ROS service service_stop with stop_handler to stop your code. Names must be service_start and service_stop.

You must use the movel_seirios_msgs package for msg and srv.

(For ROS C++ only) Add movel_seirios_msgs to package.xml and CMakeLists.txt.

Then in task_supervisor.yaml file. Change service_req: true and service_start and service_stop params to your own topics.

Stop with topic (optional)

IF you have your own script to stop the launch.

Write a subscriber topic_process_cancel to subscribe to the UI topic. Inside the handle_publish_cancel callback, include your own codes to stop.

Then change the params topic_cancel_req: true and topic_process_cancel to your own topic.

Getting status (optional)

IF you are launching your program from a launch file. Write a publisher client_status that publishes 2 if the program runs successfully or 3 if it fails.

Then change client_status: true.

3.2. Launch from the UI

Go to Custom Task UI, and choose Seirios Engine as your Execute Engine. Similarly, you need to give a task type number that is not used by other task supervisor plugins. Then, you will need a custom service_start_msg and/or service_stop_msg to run or stop your external process.

Input a Payload in the JSON format e.g. {“service_start_msg”: “/eg/payload/start”, “service_stop_msg”:”/eg/payload/stop”} to customize the parameters.

Payload has to be parsable in JSON format so remember the “ ”s.

4. Sample Codes

For reference only.

#!/usr/bin/env python3
import rospy
from movel_seirios_msgs.srv import StringTrigger, StringTriggerResponse # like setbool
from std_msgs.msg import Bool, UInt8

class Pytest:

    def __init__(self):
        print('starting test node')
        self.node = rospy.init_node('python_test')

        self.service_start = rospy.Service('/external_process/trigger_detecting', StringTrigger, self.start_handler)
        self.service_stop = rospy.Service('/external_process/stop_detecting', StringTrigger, self.stop_handler)
        
        # IGNORE dummy_publisher - just to simulate UI cancel topic
        self.dummy_publisher = rospy.Publisher('/cancel_publish', Bool, queue_size=1)

        self.topic_process_cancel = rospy.Subscriber('/cancel_publish', Bool, self.handle_publish_cancel)
        self.client_status = rospy.Publisher('/external_process/client_status', UInt8, queue_size=1)

        self.flag = True

    def start_handler(self, req):
        print('inside start handler')

        start_msg = StringTriggerResponse() 
        start_msg.success = True
        start_msg.message = 'starting detect'

        self.flag = True
        self.publish_client_status()

        while(self.flag):
            print('executing something')
            rospy.sleep(1)
    

        return start_msg # return must be [success, message format]

    def stop_handler(self, req):
        print('inside stop handler')

        self.flag = False
        print('stop handler called')
        stop_msg = StringTriggerResponse()
        stop_msg.success = False
        stop_msg.message = 'stopping detect'

        return stop_msg
    
    # IGNORE if you are not using a topic to stop your code
    def handle_publish_cancel(self, req):
        print("inside publish cancel", req.data)

        cancel_trigger = req.data
        if(cancel_trigger):
            print('executing cancel stuff') # replace print statement
    
    
    # IGNORE if you are not using launch files
    def publish_client_status(self):
        print("publish client status called")
        
        cstatus = UInt8()
        
        #Dummy code
        #Decide how do you determine if your launch file is successful
        #And replace the if-else statement
        if (self.flag == True):
            cstatus.data = 2 # if start_handler successfully called, task is successful and return 2
        else:
            cstatus.data = 3 # else task not successful, return 3

        self.client_status.publish(cstatus)


if __name__ == '__main__':

    py_test = Pytest()
    #py_test.publish_cancel()

    rospy.spin()

Last updated