Skip to the content.

🔗 Navigation


General System

System breakdown

We have decomposed the system into four interdependent subsystems:


Each Subsystem is controlled by a global controller that handles all high level logic, this was conveyed to each subsystem using ROS2 Topics, the RQT graph for communication is below: RQT

GlobalController: The Brain of the Bot

The GlobalController Python node runs in multi-threaded execution, enabling:

It handles:

Concurrency & Multithreading

The node leverages a MultiThreadedExecutor with concurrent timers and sensor callbacks, ensuring responsive, real-time robot control:

System Flow Overview

  1. Startup Phase
    Upon initialization, the robot begins in the Initializing state, waiting for valid map and sensor data. Once available, it enters the Exploratory_Mapping phase.

  2. Exploration Phase
    The robot autonomously explores the maze using frontier-based navigation. As thermal targets are detected, their global coordinates are recorded and visualized in RViz.

  3. Clustering & Goal Planning
    After the map is completed, detected heat points are clustered into goal positions. The robot then sequentially navigates to each target.

  4. Launching Phase
    At each goal, the robot stops, aligns itself, and launches a ping pong ball toward the heat source using the dual flywheel launcher.

  5. IMU Interrupt Handling
    During any phase, if a pitch anomaly is detected (e.g., going up a ramp), the system triggers the Imu_Interrupt state. The robot cancels current goals, marks unsafe zones in the occupancy grid, and replans its route.

  6. Ramp Engagement (Optional)
    If enabled, after all heat targets are engaged, the robot attempts to approach a ramp zone and perform a final launch


Sensor Fusion & Decision Logic


Communication Infrastructure

All modules interact via ROS2 topics with appropriate QoS profiles. Key topics include:

Communication is optimized for real-time response and modularity, with feedback loops embedded into every decision node.


Why This Design?

This architecture allows us to:


Extra information on State Transitions and how they are actually defined in the code

1. Transition from Initializing → Exploratory_Mapping

def initialise(self):
    self.wait_for_map()
    pos = self.get_robot_global_position()
    while pos is None:
        pos = self.get_robot_global_position()
        time.sleep(0.2)
    x , y , yaw = pos
    self.initial_yaw = yaw

2. Transition to Imu_Interrupt

def fast_loop(self):
    ...
    if self.IMU_interrupt_check() and not self.hit_ramped:
        self.set_state(GlobalController.State.Imu_Interrupt)

3. Transition from Imu_Interrupt → Exploratory_Mapping

def control_loop(self):
    ...
    elif bot_current_state == GlobalController.State.Imu_Interrupt:
        self.hit_ramped = True
        self.ramp_location = self.get_robot_grid_position()
        self.mark_area_around_robot_as_occ(self.ramp_location[0], self.ramp_location[1], 7)
        x ,y, yaw = self.previous_position[0]
        self.nav_to_goal(x,y)
        time.sleep(20)
        self.set_state(GlobalController.State.Exploratory_Mapping)

4. Transition from Exploratory_Mapping → Goal_Navigation

def control_loop(self):
    ...
    if self.finished_mapping:
        self.max_heat_locations = self.find_centers(self.clusters)
        self.set_state(GlobalController.State.Goal_Navigation)

5. Transition to Launching_Balls

def control_loop(self):
    ...
    for location in self.max_heat_locations:
        ...
        self.nav_to_goal(world_x, world_y)
        ...
        self.launch_ball()
    self.set_state(GlobalController.State.Attempting_Ramp)

6. Transition to Attempting_Ramp

def control_loop(self):
    ...
    elif bot_current_state == GlobalController.State.Goal_Navigation:
        ...
        self.set_state(GlobalController.State.Attempting_Ramp)

7. Final Ascent Handling in Attempting_Ramp

def control_loop(self):
    ...
    elif bot_current_state == GlobalController.State.Attempting_Ramp:
        x,y = self.grid_to_world(self.ramp_location[0], self.ramp_location[1])
        self.nav_to_goal(x , y, self.initial_yaw)
        time.sleep(30)
        self.run_pd_until_obstacle(self.initial_yaw)
        self.launch_ball()

Software Subsystem