Loading src/init/ros2_client.py +8 −10 Original line number Original line Diff line number Diff line Loading @@ -28,7 +28,7 @@ import html rclpy.init() rclpy.init() node = rclpy.create_node('some_client_node') node = rclpy.create_node('some_client_node') cli = node.create_client(StrReqStrRes, 'n000e64101698_master/cmd') cli = node.create_client(StrReqStrRes, 'master_1467cd/cmd') wcnt = 0 wcnt = 0 while not cli.wait_for_service(timeout_sec=1.0): while not cli.wait_for_service(timeout_sec=1.0): Loading @@ -45,10 +45,9 @@ req.request = '''<document> </document> </document> ''' ''' cli.call(req) future = cli.call_async(req) cli.wait_for_future() rclpy.spin_until_future_complete(node, future) res = future.result().response res = cli.response.response node.get_logger().info("cmd response:") node.get_logger().info("cmd response:") node.get_logger().info("\n"+res) node.get_logger().info("\n"+res) Loading @@ -63,10 +62,9 @@ req.request = '''<document> </document> </document> ''' ''' cli.call(req) future = cli.call_async(req) cli.wait_for_future() rclpy.spin_until_future_complete(node, future) res = future.result().response res = cli.response.response node.get_logger().info("cmd response:") node.get_logger().info("cmd response:") node.get_logger().info("\n"+res) node.get_logger().info("\n"+res) Loading src/init/ros2_config.py +4 −6 Original line number Original line Diff line number Diff line Loading @@ -4,15 +4,13 @@ import os import re import re import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET NODEPREFIX = 'n' # get function # get function def get(f="ros2_config.xml"): def get(f="ros2_config.xml",pre='n'): cfg = {} cfg = {} mac = get_mac(last_three_octets=False,capitalize=False) mac = get_mac(last_three_octets=True,capitalize=False) cfg['self'] = NODEPREFIX+mac cfg['self'] = pre+mac cfg['role'] = None cfg['role'] = None if os.path.isfile(f): if os.path.isfile(f): Loading src/init/ros2_master.py +102 −50 Original line number Original line Diff line number Diff line #!/usr/bin/env python3 #!/usr/bin/env python3 import asyncio import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET import xml.dom.minidom as minidom import xml.dom.minidom as minidom import rclpy from elphel_interfaces.srv import StrReqStrRes import ros2_config import urllib.parse import urllib.parse import html import html TIMEOUT = 5 import rclpy from rclpy.callback_groups import ReentrantCallbackGroup async def pass_cmd(target,cmd): cli = node.create_client(StrReqStrRes,target+'/cmd') # if n/a if not cli.wait_for_service(timeout_sec=1.0): return "<response><node>"+target+"</node><state>dead</state></response>" # if alive req = StrReqStrRes.Request() req.request = '<request><cmd>'+cmd+'</cmd></request>' cli.call(req) cli.wait_for_future() cmdres = cli.response.response return cmdres from elphel_interfaces.srv import StrReqStrRes import ros2_config TIMEOUT = 5 def parse_command(string): def parse_command(string): Loading @@ -56,57 +37,128 @@ def parse_command(string): # callback for broadcast commands # callback for broadcast commands def cmd_callback(req,res): def cmd_callback(req,res): global g_node # put async function here? async def pass_cmd(): global g_node nonlocal req nonlocal cli, did_run, did_get_result, cmd_result did_run = True try: requ = StrReqStrRes.Request() requ.request = req.request future = cli.call_async(requ) result = await future if result is not None: g_node.get_logger().info('Got response: '+result.response) else: g_node.get_logger().info('Service call failed %r' % (future.exception(),)) finally: cmd_result = result did_get_result = True # default function # default function cmd_func = pass_cmd cmd_func = pass_cmd print("The raw command is:") #print("Raw command:") print(req.request) #print(req.request) q = parse_command(req.request) q = parse_command(req.request) print("parsed command:") print("Parsed command:") print(q) print(q) if q['cmd']=='state': if q['cmd']=='state': cmd_func = pass_cmd cmd_func = pass_cmd #if q['cmd']=='status': cb_group = ReentrantCallbackGroup() # cmd_func = cmd_get_status reslist = [] tasks = [cmd_func(cfg['slaves'][c],q['cmd']) for c in q['targets']] results = event_loop.run_until_complete(asyncio.gather(*tasks)) print("Printing results:") # serial operation. TODO: make parallel print(results) for t in q['targets']: # get target by name tgt = cfg['slaves'][t] cli = g_node.create_client(StrReqStrRes, tgt+"/cmd",callback_group=cb_group) res.response = '\n'.join(results) did_run = False did_get_result = False cmdres = None cmd_result = None # if n/a if not cli.wait_for_service(timeout_sec=1.0): cmdres = "<response><node>"+tgt+"</node><state>dead</state></response>" else: # timer?! timer = g_node.create_timer(0.0, cmd_func, callback_group=cb_group) while rclpy.ok() and not did_run: rclpy.spin_once(g_node) # call timer callback only once if did_run: timer.cancel() # spin until it gets "blue" while rclpy.ok() and not did_get_result: rclpy.spin_once(g_node) cmdres = cmd_result.response # store response reslist.append(cmdres) # convert to string res.response = '\n'.join(reslist) return res return res # global # global g_node = None clients = [] clients = [] cfg = ros2_config.get() cfg = ros2_config.get(pre='master_') nodename = cfg['self']+'_master' nodename = cfg['self'] for k,v in cfg['slaves'].items(): for k,v in cfg['slaves'].items(): clients.append(k) clients.append(k) rclpy.init() rclpy.init() node = rclpy.create_node(nodename) g_node = rclpy.create_node(nodename) event_loop = asyncio.get_event_loop() print('\nStarting master services:') print('\nStarting master services:') print(' '+nodename+'/cmd') print(' '+nodename+'/cmd') s1 = node.create_service(StrReqStrRes, nodename+'/cmd', cmd_callback) s1 = g_node.create_service(StrReqStrRes, nodename+'/cmd', cmd_callback) rclpy.spin(node) while rclpy.ok(): rclpy.spin_once(g_node) # Destroy the node explicitly # Destroy the service attached to the node explicitly # (optional - Done automatically when node is garbage collected) # (optional - otherwise it will be done automatically node.destroy_node() # when the garbage collector destroys the node object) g_node.destroy_service(srv) rclpy.shutdown() rclpy.shutdown() event_loop.close() src/init/ros2_slave.py +4 −2 Original line number Original line Diff line number Diff line Loading @@ -42,10 +42,12 @@ def cmd_callback(req,res): res.response = '<response><node>'+nodename+'</node><state>'+output.decode()+'</state></response>' res.response = '<response><node>'+nodename+'</node><state>'+output.decode()+'</state></response>' print('Slave sending: '+res.response) return res return res # global # global cfg = ros2_config.get() cfg = ros2_config.get(pre='_slave_') nodename = cfg['self'] nodename = cfg['self'] Loading Loading
src/init/ros2_client.py +8 −10 Original line number Original line Diff line number Diff line Loading @@ -28,7 +28,7 @@ import html rclpy.init() rclpy.init() node = rclpy.create_node('some_client_node') node = rclpy.create_node('some_client_node') cli = node.create_client(StrReqStrRes, 'n000e64101698_master/cmd') cli = node.create_client(StrReqStrRes, 'master_1467cd/cmd') wcnt = 0 wcnt = 0 while not cli.wait_for_service(timeout_sec=1.0): while not cli.wait_for_service(timeout_sec=1.0): Loading @@ -45,10 +45,9 @@ req.request = '''<document> </document> </document> ''' ''' cli.call(req) future = cli.call_async(req) cli.wait_for_future() rclpy.spin_until_future_complete(node, future) res = future.result().response res = cli.response.response node.get_logger().info("cmd response:") node.get_logger().info("cmd response:") node.get_logger().info("\n"+res) node.get_logger().info("\n"+res) Loading @@ -63,10 +62,9 @@ req.request = '''<document> </document> </document> ''' ''' cli.call(req) future = cli.call_async(req) cli.wait_for_future() rclpy.spin_until_future_complete(node, future) res = future.result().response res = cli.response.response node.get_logger().info("cmd response:") node.get_logger().info("cmd response:") node.get_logger().info("\n"+res) node.get_logger().info("\n"+res) Loading
src/init/ros2_config.py +4 −6 Original line number Original line Diff line number Diff line Loading @@ -4,15 +4,13 @@ import os import re import re import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET NODEPREFIX = 'n' # get function # get function def get(f="ros2_config.xml"): def get(f="ros2_config.xml",pre='n'): cfg = {} cfg = {} mac = get_mac(last_three_octets=False,capitalize=False) mac = get_mac(last_three_octets=True,capitalize=False) cfg['self'] = NODEPREFIX+mac cfg['self'] = pre+mac cfg['role'] = None cfg['role'] = None if os.path.isfile(f): if os.path.isfile(f): Loading
src/init/ros2_master.py +102 −50 Original line number Original line Diff line number Diff line #!/usr/bin/env python3 #!/usr/bin/env python3 import asyncio import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET import xml.dom.minidom as minidom import xml.dom.minidom as minidom import rclpy from elphel_interfaces.srv import StrReqStrRes import ros2_config import urllib.parse import urllib.parse import html import html TIMEOUT = 5 import rclpy from rclpy.callback_groups import ReentrantCallbackGroup async def pass_cmd(target,cmd): cli = node.create_client(StrReqStrRes,target+'/cmd') # if n/a if not cli.wait_for_service(timeout_sec=1.0): return "<response><node>"+target+"</node><state>dead</state></response>" # if alive req = StrReqStrRes.Request() req.request = '<request><cmd>'+cmd+'</cmd></request>' cli.call(req) cli.wait_for_future() cmdres = cli.response.response return cmdres from elphel_interfaces.srv import StrReqStrRes import ros2_config TIMEOUT = 5 def parse_command(string): def parse_command(string): Loading @@ -56,57 +37,128 @@ def parse_command(string): # callback for broadcast commands # callback for broadcast commands def cmd_callback(req,res): def cmd_callback(req,res): global g_node # put async function here? async def pass_cmd(): global g_node nonlocal req nonlocal cli, did_run, did_get_result, cmd_result did_run = True try: requ = StrReqStrRes.Request() requ.request = req.request future = cli.call_async(requ) result = await future if result is not None: g_node.get_logger().info('Got response: '+result.response) else: g_node.get_logger().info('Service call failed %r' % (future.exception(),)) finally: cmd_result = result did_get_result = True # default function # default function cmd_func = pass_cmd cmd_func = pass_cmd print("The raw command is:") #print("Raw command:") print(req.request) #print(req.request) q = parse_command(req.request) q = parse_command(req.request) print("parsed command:") print("Parsed command:") print(q) print(q) if q['cmd']=='state': if q['cmd']=='state': cmd_func = pass_cmd cmd_func = pass_cmd #if q['cmd']=='status': cb_group = ReentrantCallbackGroup() # cmd_func = cmd_get_status reslist = [] tasks = [cmd_func(cfg['slaves'][c],q['cmd']) for c in q['targets']] results = event_loop.run_until_complete(asyncio.gather(*tasks)) print("Printing results:") # serial operation. TODO: make parallel print(results) for t in q['targets']: # get target by name tgt = cfg['slaves'][t] cli = g_node.create_client(StrReqStrRes, tgt+"/cmd",callback_group=cb_group) res.response = '\n'.join(results) did_run = False did_get_result = False cmdres = None cmd_result = None # if n/a if not cli.wait_for_service(timeout_sec=1.0): cmdres = "<response><node>"+tgt+"</node><state>dead</state></response>" else: # timer?! timer = g_node.create_timer(0.0, cmd_func, callback_group=cb_group) while rclpy.ok() and not did_run: rclpy.spin_once(g_node) # call timer callback only once if did_run: timer.cancel() # spin until it gets "blue" while rclpy.ok() and not did_get_result: rclpy.spin_once(g_node) cmdres = cmd_result.response # store response reslist.append(cmdres) # convert to string res.response = '\n'.join(reslist) return res return res # global # global g_node = None clients = [] clients = [] cfg = ros2_config.get() cfg = ros2_config.get(pre='master_') nodename = cfg['self']+'_master' nodename = cfg['self'] for k,v in cfg['slaves'].items(): for k,v in cfg['slaves'].items(): clients.append(k) clients.append(k) rclpy.init() rclpy.init() node = rclpy.create_node(nodename) g_node = rclpy.create_node(nodename) event_loop = asyncio.get_event_loop() print('\nStarting master services:') print('\nStarting master services:') print(' '+nodename+'/cmd') print(' '+nodename+'/cmd') s1 = node.create_service(StrReqStrRes, nodename+'/cmd', cmd_callback) s1 = g_node.create_service(StrReqStrRes, nodename+'/cmd', cmd_callback) rclpy.spin(node) while rclpy.ok(): rclpy.spin_once(g_node) # Destroy the node explicitly # Destroy the service attached to the node explicitly # (optional - Done automatically when node is garbage collected) # (optional - otherwise it will be done automatically node.destroy_node() # when the garbage collector destroys the node object) g_node.destroy_service(srv) rclpy.shutdown() rclpy.shutdown() event_loop.close()
src/init/ros2_slave.py +4 −2 Original line number Original line Diff line number Diff line Loading @@ -42,10 +42,12 @@ def cmd_callback(req,res): res.response = '<response><node>'+nodename+'</node><state>'+output.decode()+'</state></response>' res.response = '<response><node>'+nodename+'</node><state>'+output.decode()+'</state></response>' print('Slave sending: '+res.response) return res return res # global # global cfg = ros2_config.get() cfg = ros2_config.get(pre='_slave_') nodename = cfg['self'] nodename = cfg['self'] Loading