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:
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: 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.
- {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.
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
print('executing something')
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",
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): = 2 # if start_handler successfully called, task is successful and return 2
else: = 3 # else task not successful, return 3
if __name__ == '__main__':
py_test = Pytest()
#include <ros/ros.h>
#include <std_msgs/Bool.h>
#include <std_msgs/UInt8.h>
#include <movel_seirios_msgs/StringTrigger.h>
class Cpptest {
ros::ServiceServer service_start;
ros::ServiceServer service_stop;
ros::Publisher dummy_publisher;
ros::Subscriber topic_process_cancel;
ros::Publisher client_status;
bool flag;
Cpptest(ros::NodeHandle *nh) {
service_start = nh->advertiseService("/external_package/triggering_detect_cpp", &Cpptest::start_handler, this);
service_stop = nh->advertiseService("/external_package/stopping_detect_cpp", &Cpptest::stop_handler, this);
// Ignore dummy_publisher - just to simulate ui cancel button
dummy_publisher = nh->advertise<std_msgs::Bool>("/cancel_publish_cpp", 10);
topic_process_cancel = nh->subscribe("/cancel_publish_cpp", 1, &Cpptest::handle_publish_cancel, this);
client_status = nh->advertise<std_msgs::UInt8>("/external_process/client_status_cpp", 10);
bool start_handler(movel_seirios_msgs::StringTrigger::Request &req, movel_seirios_msgs::StringTrigger::Response &res) {
std::cout << "inside start handler\n";
res.success = true;
res.message = "starting detect";
//std::cout << res << "\n";
flag = true;
std::cout << "start handler flag "<< flag << "\n";
return true;
bool stop_handler(movel_seirios_msgs::StringTrigger::Request &req, movel_seirios_msgs::StringTrigger::Response &res) {
std::cout << "inside stop handler\n";
res.success = false;
res.message = "stopping detect";
//std::cout << res << "\n";
flag = false;
std::cout << "stop handler flag "<< flag << "\n";
return true;
// Ignore this method if not subscribing to stop topic
void handle_publish_cancel(const std_msgs::Bool& msg) {
std::cout << "inside handle publish cancel\n";
bool cancel_trigger;
cancel_trigger =;
//std::cout << "published msg " << cancel_trigger << "\n";
std::cout << "do canceling stuff. cancel_trigger: " << cancel_trigger << "\n";
// Ignore this method if not using launch
void publish_client_status() {
std::cout << "publish client status called\n";
std_msgs::UInt8 cstatus;
if(flag) { = 2;
else { = 3;
std::cout << "client status " << cstatus << "2 for success, 3 for fail \n";
int main(int argc, char** argv) {
ros::init(argc, argv, "cpp_test");
ros::NodeHandle nh;
Cpptest cpp_test(&nh);
return 0;