Path Recording & Replay¶
Save successful paths and re-execute them on demand.
Sometimes you don’t need a dynamic planner to calculate a new path every time. In scenarios like routine patrols, warehousing, or repeatable docking, it is often more reliable to record a “golden path” once and replay it exactly.
The Planner component facilitates this via three ROS 2 services:
save_plan_to_file: Saves the currently active plan (or recorded history) to a CSV file.load_plan_from_file: Loads a CSV file and publishes it as the current global plan.start_path_recording: Starts recording the robot’s actual odometry history to be saved later.
The Recipe¶
This recipe sets up a basic navigation stack but exposes the Save/Load/Record Services to the Web UI instead of the standard “Click-to-Nav” action.
Create a file named path_recorder.py:
import numpy as np
import os
from ament_index_python.packages import get_package_share_directory
# Kompass Imports
from kompass.robot import (
AngularCtrlLimits, LinearCtrlLimits, RobotGeometry, RobotType, RobotConfig, RobotFrames
)
from kompass.components import (
DriveManager, DriveManagerConfig, Planner, PlannerConfig,
MapServer, MapServerConfig, TopicsKeys, Controller
)
from kompass.ros import Topic, Launcher, ServiceClientConfig
from kompass.control import ControllersID
from kompass_interfaces.srv import PathFromToFile, StartPathRecording
def run_path_recorder():
kompass_sim_dir = get_package_share_directory(package_name="kompass_sim")
# 1. Robot Configuration
my_robot = RobotConfig(
model_type=RobotType.DIFFERENTIAL_DRIVE,
geometry_type=RobotGeometry.Type.CYLINDER,
geometry_params=np.array([0.1, 0.3]),
ctrl_vx_limits=LinearCtrlLimits(max_vel=0.4, max_acc=1.5, max_decel=2.5),
ctrl_omega_limits=AngularCtrlLimits(max_vel=0.4, max_acc=2.0, max_decel=2.0, max_steer=np.pi / 3),
)
# 2. Configure Components
planner = Planner(component_name="planner", config=PlannerConfig(loop_rate=1.0))
planner.run_type = "Timed"
controller = Controller(component_name="controller")
controller.algorithm = ControllersID.PURE_PURSUIT
controller.direct_sensor = True # Use direct sensor for simple obstacle checks
driver = DriveManager(
component_name="drive_manager",
config=DriveManagerConfig(critical_zone_distance=0.05)
)
# Handle message types (Twist vs TwistStamped)
cmd_msg_type = "TwistStamped" if os.environ.get("ROS_DISTRO") in ["rolling", "jazzy", "kilted"] else "Twist"
driver.outputs(robot_command=Topic(name="/cmd_vel", msg_type=cmd_msg_type))
map_server = MapServer(
component_name="global_map_server",
config=MapServerConfig(
map_file_path=os.path.join(kompass_sim_dir, "maps", "turtlebot3_webots.yaml"),
grid_resolution=0.5
)
)
# 3. Define Services for UI Interaction
save_path_srv = ServiceClientConfig(
name=f"{planner.node_name}/save_plan_to_file", srv_type=PathFromToFile
)
load_path_srv = ServiceClientConfig(
name=f"{planner.node_name}/load_plan_from_file", srv_type=PathFromToFile
)
start_path_recording = ServiceClientConfig(
name=f"{planner.node_name}/start_path_recording", srv_type=StartPathRecording
)
# 4. Launch
launcher = Launcher()
launcher.kompass(
components=[map_server, planner, driver, controller],
multiprocessing=True,
)
odom_topic = Topic(name="/odometry/filtered", msg_type="Odometry")
launcher.inputs(location=odom_topic)
launcher.robot = my_robot
launcher.frames = RobotFrames(world="map", odom="map", scan="LDS-01")
# 5. Enable UI
launcher.enable_ui(
inputs=[save_path_srv, load_path_srv, start_path_recording],
outputs=[
map_server.get_out_topic(TopicsKeys.GLOBAL_MAP),
odom_topic,
planner.get_out_topic(TopicsKeys.GLOBAL_PLAN),
],
)
launcher.bringup()
if __name__ == "__main__":
run_path_recorder()
Workflow: Two Ways to Generate a Path¶
Once the recipe is running and you have the Kompass UI open (http://0.0.0.0:5001), you can generate a path using either the planner or by manually driving the robot.
Option A: Save a Computed Plan¶
Use this if you want to save the path produced by the global planner and you want to “freeze” that exact path for future use.
Generate Plan: Trigger the planner (e.g., via the
/clicked_pointinput on the UI).Verify: Check if the generated path looks good…
Save: In the UI Inputs panel, go to the
planner/save_plan_to_filein the Inputs panel
Enter the file_location:
/tmp/and file_name:computed_path.jsonClick Send.
Option B: Record a Driven Path (Teleop)¶
Use this if you want the robot to follow a human-demonstrated path (e.g., a specific maneuver through a tight doorway).
Start Recording: In the UI Inputs panel, select
planner/start_path_recording.
recording_time_step:
0.1(Records a point every 0.1 seconds).Click Call.
Drive: Use your keyboard or joystick (e.g.,
ros2 run teleop_twist_keyboard teleop_twist_keyboard) to drive the robot along the desired route.Save: When finished, select
planner/save_plan_to_file.
Enter the file_location:
/tmp/and file_name:computed_path.csvClick Send. (Note: Calling save automatically stops the recording process).
Replay the Path¶
Now that you have your “Golden Path” saved (either computed or recorded), you can replay it anytime.
Restart: You can restart the stack or simply clear the current plan.
Load: In the UI Inputs panel, select
planner/load_plan_from_file.
file_location:
/tmp/file_name:
driven_path.csv(orcomputed_path.csv)Click Send.
Result: The planner immediately loads the CSV file and publishes it as the Global Plan. The Controller receives this path and begins executing it immediately, retracing your steps exactly.
Use Cases¶
Routine Patrols: Record a perfect lap around a facility and replay it endlessly.
Complex Docking: Manually drive a complex approach to a charging station, save the plan, and use it for reliable docking.
Multi-Robot Coordination: Share a single “highway” path file among multiple robots to ensure they stick to verified lanes.