9 from std_srvs.srv
import Trigger, TriggerResponse
10 from vizanti.srv
import GetNodeParameters, GetNodeParametersResponse
11 from vizanti.srv
import LoadMap, LoadMapResponse, SaveMap, SaveMapResponse
12 from vizanti.srv
import RecordRosbag, RecordRosbagResponse
13 from vizanti.srv
import ManageNode, ListPackages, ListExecutables, ListExecutablesResponse, ListPackagesResponse
19 rospy.init_node(
'vizanti_service_handler')
24 self.
get_nodes_service = rospy.Service(
'vizanti/get_dynamic_reconfigure_nodes', Trigger,self. get_dynamic_reconfigure_nodes)
41 rospy.loginfo(
"Service handler ready.")
45 cmd = [
"rospack",
"list"]
46 process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
47 output, error = process.communicate()
49 lines = output.decode(
'utf-8').split(
'\n')
50 packages = {line.split()[0]: line.split()[1]
for line
in lines
if line}
54 return ListPackagesResponse(self.
packages.keys())
58 rospy.logerr(
"Package not found: " + req.package)
59 return ListExecutablesResponse([])
63 cmd_exec = [
"find", path,
"-type",
"f",
"!",
"-name",
"*.*",
"-executable"]
64 cmd_python_and_launch = [
"find", path,
"-type",
"f",
66 "-iname",
"*.py",
"-executable",
71 process_exec = subprocess.Popen(cmd_exec, stdout=subprocess.PIPE)
72 process_python_and_launch = subprocess.Popen(cmd_python_and_launch, stdout=subprocess.PIPE)
74 output_exec, error_exec = process_exec.communicate()
75 output_python_and_launch, error_python_and_launch = process_python_and_launch.communicate()
78 lines_exec = output_exec.decode(
'utf-8').split(
'\n')
79 lines_python_and_launch = output_python_and_launch.decode(
'utf-8').split(
'\n')
81 executables = [line.split(
"/")[-1]
for line
in lines_exec
if line]
82 python_and_launch_files = [line.split(
"/")[-1]
for line
in lines_python_and_launch
if line]
84 return ListExecutablesResponse(executables + python_and_launch_files)
88 subprocess.call([
'rosnode',
'kill', req.node])
89 return {
'success':
True,
'message': f
'Killed node {req.node}'}
90 except Exception
as e:
91 return {
'success':
False,
'message': str(e)}
95 args = req.node.split(
" ")
98 devnull = open(os.devnull,
'w')
103 sys.stdin = open(os.devnull,
'r')
104 sys.stdout = open(os.devnull,
'w')
105 sys.stderr = open(os.devnull,
'w')
107 subprocess.Popen(args, stdout=devnull, stderr=devnull, preexec_fn=preexec)
109 return {
'success':
True,
'message': f
'Started node {req.node}'}
110 except Exception
as e:
111 return {
'success':
False,
'message': str(e)}
115 rosinfo = subprocess.check_output([
"rosnode",
"info", req.node]).decode(
'utf-8')
116 rosinfo = rosinfo.replace(
"--------------------------------------------------------------------------------",
"")
117 return {
'success':
True,
'message': rosinfo}
118 except Exception
as e:
119 return {
'success':
False,
'message': str(e)}
123 rosinfo = subprocess.check_output([
"roswtf"]).decode(
'utf-8')
124 return {
'success':
True,
'message': rosinfo}
125 except Exception
as e:
126 return {
'success':
False,
'message': str(e)}
130 file_path = os.path.expanduser(req.file_path)
133 process = subprocess.Popen([
"rosrun",
"map_server",
"map_server", file_path,
"map:=" + topic,
"__name:=vizanti_map_server"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
134 flags = fcntl.fcntl(process.stdout, fcntl.F_GETFL)
135 fcntl.fcntl(process.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
141 if process.poll()
is not None:
143 error_output = process.stdout.read().decode(
'utf-8')
144 return LoadMapResponse(success=
False, message=
"Map server failed to load the map: " + error_output)
146 return LoadMapResponse(success=
True, message=
"Map loaded successfully")
147 except Exception
as e:
148 return LoadMapResponse(success=
False, message=str(e))
151 file_path = os.path.expanduser(req.file_path)
154 process = subprocess.Popen([
"rosrun",
"map_server",
"map_saver",
"-f", file_path,
"map:=" + topic,
"__name:=vizanti_map_saver"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
155 flags = fcntl.fcntl(process.stdout, fcntl.F_GETFL)
156 fcntl.fcntl(process.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
160 if process.poll()
is not None:
165 line = process.stdout.readline()
169 if b
"[ERROR]" in line:
171 return SaveMapResponse(success=
False, message=
"Map saver failed to save the map: " + line.decode(
'utf-8'))
178 return SaveMapResponse(success=
True, message=
"Map saved successfully")
179 except Exception
as e:
180 return SaveMapResponse(success=
False, message=str(e))
183 list_nodes_output = subprocess.check_output([
"rosrun",
"dynamic_reconfigure",
"dynparam",
"list"]).decode(
'utf-8')
184 nodes_list = list_nodes_output.strip().split(
"\n")
186 response = TriggerResponse()
187 response.success =
True
188 response.message =
"\n".join(nodes_list)
193 node_params = subprocess.check_output([
"rosrun",
"dynamic_reconfigure",
"dynparam",
"get", req.node]).decode(
'utf-8')
195 response = GetNodeParametersResponse()
196 response.parameters = node_params
201 response = TriggerResponse()
202 response.success = self.
proc is not None
205 response.message =
"Bag recording in progress..."
207 response.message =
"Bag recorder idle."
214 response = RecordRosbagResponse()
217 if self.
proc is not None:
218 response.success =
False
219 response.message =
"Already recording, please stop the current recording first."
221 command = [
'rosbag',
'record',
'-O']
224 expanded_path = os.path.expanduser(req.path)
225 command.append(expanded_path)
228 for topic
in req.topics:
229 command.append(topic)
232 self.
proc = subprocess.Popen(command)
234 response.success =
True
235 response.message =
"Started recording rosbag with PID " + str(self.
proc.pid) +
" to path "+ str(expanded_path)
237 if self.
proc is None:
238 response.success =
False
239 response.message =
"No recording to stop."
241 self.
proc.terminate()
244 response.success =
True
245 response.message =
"Stopped recording rosbag."