.. _examples: ROS-Aseba: examples =================== Setup ----- To reproduce a multi-robot network (two Thymios with id 14031 and 21181, and two e-pucks with id 1 and 2), launch `Aseba Playground `_ .. code-block:: console asebaplayground and open the world at ``ros-aseba/asebaros_examples/launch/simulation/multirobot.playground`` .. code-block:: xml A simple multi-robot playground to experiment with asebaros without physical robots. Use `Aseba Switch `_ to make the robots join the same network at port 33333. .. code-block:: console asebaswitch "tcp:host=localhost\;port=33334\;remapLocal=21181\;remapTarget=1" "tcp:host=localhost\;port=33335\;remapLocal=14031\;remapTarget=1" "tcp:host=localhost\;port=33336\;remapLocal=1\;remapTarget=1" "tcp:host=localhost\;port=33337\;remapLocal=2\;remapTarget=1" -p 33333 With this setup ``DEVICE="tcp:host=localhost;port=33333"``. To execute any ROS command, you have first to source the ROS setup script .. tabs:: .. code-tab:: bash Linux or macOS source /install/setup.bash .. code-tab:: shell Windows C:\install\setup.bat .. note:: The examples below works with any other Aseba network, and in particular with real robots too. In this case, just change the ids and add ``device:=`` to the ROS launch arguments (e.g., ``device:="ser:name=Thymio"`` to connect a Thymio). All nodes ---------- The following launch files configure ``asebaros`` to connect to all nodes at Dashel target ``device``. Each node will receive a ROS namespace ``"node_{id}"``. No script will be automatically loaded into the nodes. .. tabs:: .. code-tab:: xml ROS1 ["$(arg device)",] any: accept: true prefix: node_ .. code-tab:: xml ROS2 Launch it with .. tabs:: .. code-tab:: console ROS1 roslaunch asebaros_examples all_nodes.launch .. code-tab:: console ROS2 ros2 launch asebaros_examples all_nodes.launch Inspect the system using services: 1. Get the list of nodes .. tabs:: .. code-tab:: console ROS1 rosservice call /aseba/get_nodes asebaros_msgs/GetNodeList '{}' .. code-tab:: console ROS2 ros2 service call /aseba/get_nodes asebaros_msgs/GetNodeList '{}' 2. Get the description of one of the nodes .. tabs:: .. code-tab:: console ROS1 rosservice call /node_14031/aseba/get_description asebaros_msgs/GetDescription '{}' .. code-tab:: console ROS2 ros2 service call /node_14031/aseba/get_description asebaros_msgs/GetDescription '{}' 3. Get the value of a variable .. tabs:: .. code-tab:: console ROS1 rosservice call /node_14031/aseba/get_variable asebaros_msgs/GetVariable "{variable: prox.horizontal}" .. code-tab:: console ROS2 ros2 service call /node_14031/aseba/get_variable asebaros_msgs/GetVariable "{variable: prox.horizontal}" 4. Set the value of a variable .. tabs:: .. code-tab:: console ROS1 rosservice call /node_14031/aseba/set_variable asebaros_msgs/SetVariable "{variable: motor.left.target, data: [100]}" .. code-tab:: console ROS2 ros2 service call /node_14031/aseba/set_variable asebaros_msgs/SetVariable "{variable: motor.left.target, data: [100]}" A single node ------------- The following launch files configure ``asebaros`` to connect to just the first Thymio (i.e., the first Aseba node with ``name=="thymio-II"``) .. tabs:: .. code-tab:: xml ROS1 ["$(arg device)",] others: accept: false thymio: name: thymio-II id_variable: _id accept: true include_id_in_events: false maximal_number: 1 path: $(find asebaros_examples)/launch/single_node.aesl constants: MY_CONSTANT: 3 .. code-tab:: xml ROS2 The node will receive an empty ROS namespace and a script will be automatically loaded into the node. The script has a single constant ``MY_CONSTANT``, which the launch file sets to ``3``, and two events: ``ping`` and ``pong``. .. code-block:: xml var value[3] = [MY_CONSTANT, MY_CONSTANT, MY_CONSTANT] emit pong value onevent ping value = event.args[0:2] emit pong value The events are used to make the robot "pong" back the values (an array of length 3) sent with the ping. Launch it with .. tabs:: .. code-tab:: console ROS1 roslaunch asebaros_examples single_node.launch .. code-tab:: console ROS2 ros2 launch asebaros_examples single_node.launch In a new tab send a ping each second .. tabs:: .. code-tab:: console ROS1 rostopic pub -r 1 /aseba/events/ping asebaros_msgs/Event '{data: [1, 2, 3]}' .. code-tab:: console ROS2 ros2 topic pub -r 1 /aseba/events/ping asebaros_msgs/Event '{data: [1, 2, 3]}' and in another one, listen for pongs .. tabs:: .. code-tab:: console ROS1 rostopic echo /aseba/events/pong .. code-tab:: console ROS2 ros2 topic echo /aseba/events/pong Twin nodes ---------- In this case, we want to connect to *all* nodes and load the same script. Each node will receive a namespace ``"node_{id}"``. .. tabs:: .. code-tab:: xml ROS1 ["$(arg device)",] any: prefix: node_ accept: true include_id_in_events: true thymio: name: thymio-II id_variable: _id epuck: name: e-puck0 id_variable: id path: $(find asebaros_examples)/launch/twin_nodes.aesl constants: MY_CONSTANT: 3 .. code-tab:: xml ROS2 Because the id of the target node is included in the event ``ping`` (``include_id_in_events=true``), the script can check if the event is addressed at the current node, and *only in this case* "pong" back. .. code-block:: xml var value[3] = [MY_CONSTANT, MY_CONSTANT, MY_CONSTANT] emit pong value onevent ping if (event.args[0] == _id) then value = event.args[1:3] emit pong value end Launch ROS with .. tabs:: .. code-tab:: console ROS1 roslaunch asebaros_examples twin_nodes.launch .. code-tab:: console ROS2 ros2 launch asebaros_examples twin_nodes.launch In a new tab send pings each second to a specific robot .. tabs:: .. code-tab:: console ROS1 rostopic pub -r 1 /node_14031/aseba/events/ping asebaros_msgs/Event '{data: [1, 2, 3]}' .. code-tab:: console ROS2 ros2 topic pub -r 1 /node_14031/aseba/events/ping asebaros_msgs/Event '{data: [1, 2, 3]}' and in another one, listen for pongs from different robots .. tabs:: .. code-tab:: console ROS1 ros2 topic echo /node_14031/aseba/events/pong ros2 topic echo /node_21181/aseba/events/pong .. code-tab:: console ROS2 ros2 topic echo /node_14031/aseba/events/pong ros2 topic echo /node_21181/aseba/events/pong Two nodes --------- In this case, we want to connect to two nodes of different types. As the different nodes uses different [incoming] events, we don't need to include the node id in the event. .. tabs:: .. code-tab:: xml ROS1 ["$(arg device)",] others: accept: false thymio: name: thymio-II id_variable: _id accept: true namespace: thymio include_id_in_events: false maximal_number: 1 epuck: name: e-puck0 id_variable: id accept: true namespace: epuck include_id_in_events: false maximal_number: 1 path: $(find asebaros_examples)/launch/two_nodes.aesl constants: MY_CONSTANT_THYMIO: 3 MY_CONSTANT_EPUCK: 333 .. code-tab:: xml ROS2 .. code-block:: xml var value[3] = [MY_CONSTANT_THYMIO, MY_CONSTANT_THYMIO, MY_CONSTANT_THYMIO] emit pong value onevent ping_thymio value = event.args[0:2] emit pong value var value[3] = [MY_CONSTANT_EPUCK, MY_CONSTANT_EPUCK, MY_CONSTANT_EPUCK] emit pong value onevent ping_epuck value = args[0:2] emit pong value Launch ROS with .. tabs:: .. code-tab:: console ROS1 roslaunch asebaros_examples two_nodes.launch .. code-tab:: console ROS2 ros2 launch asebaros_examples two_nodes.launch In a new tab send pings each second to a specific robot .. tabs:: .. code-tab:: console ROS1 rostopic pub -r 1 /epuck/aseba/events/ping_epuck asebaros_msgs/Event '{data: [1, 2, 3]}' .. code-tab:: console ROS2 ros2 topic pub -r 1 /epuck/aseba/events/ping_epuck asebaros_msgs/Event '{data: [1, 2, 3]}' and in another one, listen for pongs .. tabs:: .. code-tab:: console ROS1 rostopic echo /epuck/aseba/events/pong .. code-tab:: console ROS2 ros2 topic echo /epuck/aseba/events/pong A single Thymio --------------- The following launch files configure asebaros to connect to just the first Thymio (i.e., the first Aseba node with ``name=="thymio-II"``), and a script will be automatically loaded into the node. .. tabs:: .. code-tab:: xml ROS1 ["$(arg device)",] others: accept: false thymio: type: thymio-II id_variable: _id accept: true name: thymio include_id_in_events: false maximal_number: 1 path: $(find asebaros_examples)/launch/single_thymio.aesl constants: OBSTACLE_THRESHOLD: 2500 .. code-tab:: xml ROS2 This time, the node will receive a ROS namespace ``thymio`` and the script is specific for the Thymio. .. code-block:: xml onevent prox if (prox.horizontal[2] > OBSTACLE_THRESHOLD) then call leds.buttons(32, 32, 32, 32) emit obstacle else call leds.buttons(0, 0, 0, 0) end onevent set_color call leds.top(event.args[0], event.args[1], event.args[2]) The constant ``OBSTACLE_THRESHOLD`` controls the onboard behavior that makes the Thymio turn on the button LED to signal a close object. The ``obstacle`` event is used to notify ROS of an obstacle while the ``set_color`` event is used by ROS to change the Thymio body color. Launch ROS with .. tabs:: .. code-tab:: console ROS1 roslaunch asebaros_examples single_thymio.launch .. code-tab:: console ROS2 ros2 launch asebaros_examples single_thymio.launch In a new tab set the body LED of the Thymio to cyan .. tabs:: .. code-tab:: console ROS1 rostopic pub --once /thymio/aseba/events/set_color asebaros_msgs/Event '{data: [0, 32, 32]}' .. code-tab:: console ROS2 ros2 topic pub --once /thymio/aseba/events/set_color asebaros_msgs/Event '{data: [0, 32, 32]}' and in another one, listen for obstacles (move around the cyan robot) .. tabs:: .. code-tab:: console ROS1 rostopic echo /thymio/aseba/events/obstacle .. code-tab:: console ROS2 ros2 topic echo /thymio/aseba/events/obstacle Twin Thymios --------------- We want to connect to any Thymio in the network and load the same script. Each of them will get the namespace ``"thymio_{id}"``. .. tabs:: .. code-tab:: xml ROS1 ["$(arg device)",] others: accept: false thymio: name: thymio-II id_variable: _id accept: true prefix: thymio_ include_id_in_events: true path: $(find asebaros_examples)/launch/twin_thymios.aesl constants: OBSTACLE_THRESHOLD: 2500 .. code-tab:: xml ROS2 Because the paramer ``include_id_in_events`` is set to ``true``, ``asebaros`` will include the [target] robot id in the event ``set_color``. The script checks that the command targets the current robot, else it ignores it. .. code-block:: xml onevent prox if (prox.horizontal[2] > OBSTACLE_THRESHOLD) then call leds.buttons(32, 32, 32, 32) emit obstacle else call leds.buttons(0, 0, 0, 0) end onevent set_color if (event.args[0] == _id) then call leds.top(event.args[1], event.args[2], event.args[3]) end Launch ROS with .. tabs:: .. code-tab:: console ROS1 roslaunch asebaros_examples twin_thymios.launch .. code-tab:: console ROS2 ros2 launch asebaros_examples twin_thymios.launch In a new tab set the body LED of Thymio to cyan and of the other to yellow .. tabs:: .. code-tab:: console ROS1 rostopic pub --once /thymio_14031/aseba/events/set_color asebaros_msgs/Event '{data: [32, 32, 0]}' rostopic pub --once /thymio_21181/aseba/events/set_color asebaros_msgs/Event '{data: [0, 32, 32]}' .. code-tab:: console ROS2 ros2 topic pub --once /thymio_14031/aseba/events/set_color asebaros_msgs/Event '{data: [0, 32, 32]}' ros2 topic pub --once /thymio_21181/aseba/events/set_color asebaros_msgs/Event '{data: [32, 32, 0]}' Two Thymios ----------- In this example, we want connect to two specific Thymio identified by id, assign them to predefined namespaces (Thymio 21181 to ``"red"`` and Thymio 14031 to ``"green"``), and automatically set their body LED color coherently. .. tabs:: .. code-tab:: xml ROS1 ["$(arg device)",] others: accept: false thymio: name: thymio-II id_variable: _id accept: false include_id_in_events: false thymio_21181: id: 21181 name: thymio-II accept: true namespace: red thymio_14031: id: 14031 name: thymio-II accept: true namespace: green path: $(find asebaros_examples)/launch/two_thymios.aesl .. code-tab:: xml ROS2 Different code get uploaded to each of them: one will turn red, while the other green. .. code-block:: xml call leds.top(32, 0, 0) call leds.top(0, 32, 0) Launch ROS with .. tabs:: .. code-tab:: console ROS1 roslaunch asebaros_examples two_thymios.launch .. code-tab:: console ROS2 ros2 launch asebaros_examples two_thymios.launch Check that the correct namespaces are being used .. tabs:: .. code-tab:: console ROS1 rostopic list .. code-tab:: console ROS2 ros2 topic list