==================================================== Exercises ==================================================== This page contains three take-home exercises that reinforce the concepts from Lecture 12. Each exercise asks you to **write code from scratch** based on a specification -- no starter code is provided. All files should be created inside your ``~/enpm605_ws/src/`` workspace in the appropriate packages (``namespace_demo``, ``remapping_demo``, or ``bt_demo``). .. dropdown:: Exercise 1 -- Multi-Camera Namespace Launch :icon: gear :class-container: sd-border-primary :class-title: sd-font-weight-bold **Goal** Write a launch file that starts **three** instances of the same camera node, each in a different namespace, and verify they are fully isolated. .. raw:: html
**Specification** Create a launch file at ``namespace_demo/launch/three_cameras.launch.py`` that: 1. Starts three ``camera_demo_exe`` nodes under namespaces ``/front``, ``/left``, and ``/right``. 2. Each node must use ``output="screen"`` and ``emulate_tty=True``. **Verification:** .. code-block:: console ros2 launch namespace_demo three_cameras.launch.py In a second terminal: .. code-block:: console ros2 node list # Expected: /front/camera_node, /left/camera_node, /right/camera_node ros2 topic list # Expected: /front/image_raw, /left/image_raw, /right/image_raw rqt_graph # Three isolated publisher nodes, no cross-talk .. dropdown:: Exercise 2 -- Add a New Condition Node to the BT :icon: gear :class-container: sd-border-primary :class-title: sd-font-weight-bold **Goal** Add a ``MaxDistanceTraveled`` condition node to the behavior tree that stops the robot after it has traveled a configurable maximum distance. .. raw:: html
**Specification** Create ``bt_demo/bt_demo/max_distance.py`` that implements: 1. A ``MaxDistanceTraveled`` class inheriting from ``py_trees.behaviour.Behaviour``. 2. Constructor takes ``name`` and ``max_distance`` (float, meters). 3. In ``setup()``, subscribe to ``/odometry/filtered``. 4. Track the cumulative distance traveled by computing the Euclidean distance between consecutive odometry readings. 5. In ``update()``: - Return ``SUCCESS`` if the total distance is below ``max_distance`` (robot can keep going). - Return ``FAILURE`` if the total distance exceeds ``max_distance`` (robot should stop). 6. Add this condition to the root Sequence in ``main_drive_to_goal.py``, **before** the ``GoalNotReached?`` condition: .. code-block:: text Sequence (DriveToGoal, memory=False) |-- MaxDistanceTraveled? [NEW] |-- GoalNotReached? |-- Selector (DriveOrRecover, memory=True) |-- ... **Verification:** .. code-block:: console ros2 launch bt_demo drive_to_goal.py goal_x:=100.0 max_distance:=3.0 The robot should stop after approximately 3 meters, even though the goal is 100 meters away. .. dropdown:: Exercise 3 -- Topic Remapping with Multiple Subscribers :icon: gear :class-container: sd-border-primary :class-title: sd-font-weight-bold **Goal** Create a launch file that connects two camera publishers to a single image processor subscriber using topic remapping. .. raw:: html
**Specification** Create ``remapping_demo/launch/multi_remap.launch.py`` that: 1. Starts two ``camera_demo_exe`` nodes with names ``front_camera`` and ``rear_camera``. 2. Remaps their topics: - ``front_camera``: ``image_raw`` -> ``/sensors/front/image`` - ``rear_camera``: ``image_raw`` -> ``/sensors/rear/image`` 3. Starts two ``image_processor_exe`` nodes with names ``front_processor`` and ``rear_processor``. 4. Remaps their subscriptions: - ``front_processor``: ``camera/image`` -> ``/sensors/front/image`` - ``rear_processor``: ``camera/image`` -> ``/sensors/rear/image`` **Verification:** .. code-block:: console ros2 launch remapping_demo multi_remap.launch.py In a second terminal: .. code-block:: console ros2 topic list # Expected: /sensors/front/image and /sensors/rear/image rqt_graph # front_camera -> /sensors/front/image -> front_processor # rear_camera -> /sensors/rear/image -> rear_processor