neo_docking2 - Contour Matching Based Docking

neo_docking2 is a ROS 2 package and the spiritual successor of neo_docking.

Like neo_docking, neo_docking2 enables the Neobotix robot to autonomously dock with the charging station. However, unlike its predecessor, neo_docking2 does not rely on a depth camera or QR tags to detect the coordinates of the charging contacts. Instead, it uses contour matching—based on one of the ICP (Iterative Closest Point) methods—to determine the docking position. It also switches the safety fields of the Flexisoft system to proceed with docking.

Attention

This documentation describes neo_docking2 version 1.0, released in September 2026. If you need documentation for an older version or assistance with an upgrade, please contact us directly via email or open an issue on the neo_docking2 GitHub repository.

Attention

This package is supported only for Jazzy and above.

The following instructions provide an overview of how the ROX robot docks with the Wallbox.

Attention

It is recommended to read the hardware documentation for the Wallbox before continuing with this tutorial.

Installation

  1. Install the ROS 2 PCL libraries. Open a terminal on the ROX robot and run:

    sudo apt install ros-$ROS_DISTRO-pcl-ros ros-$ROS_DISTRO-pcl-conversions
    
  2. Clone the neo_docking2 package:

    cd ~/ros2_workspace/src
    git clone https://github.com/neobotix/neo_docking2.git
    

    Switch to the branch jazzy

    Note

    In the release version, the checkout step will be removed.

  3. Unzip the neo_perception2 zip file and add the folder containing the binaries to the install directory of your workspace.

Attention

neo_perception2 is a closed-source package. The version delivered with the Wallbox is restricted to detecting and docking with the Wallbox only.

  1. Source the installation package from the root of your workspace:

    cd ~/ros2_workspace
    . install/setup.base
    
  2. Build the package:

    colcon build --symlink-install
    
  3. Adjusting the navigation goal tolerance:

    In the navigation configuration, please make sure the xy_goal_tolerance is set to 0.01. The config files can be founder under ~/ros2_workspace/src/rox/rox_navigation/configs.

Parameters

Important

The platform-specific offset values must be calibrated for the robot and Wallbox installation. Do not copy offsets from another platform.

The parameters are configured in neo_docking2/launch/dock_param.yaml.

Docking parameters

  • scan_topic: sensor_msgs/msg/LaserScan topic used for contour matching.
  • offset_x, offset_y: Hardware-derived position of the docking frame relative to the recorded Wallbox contour, in metres. The values depend on the robot, scanner mounting and Wallbox contact geometry; they are not coordinates in the map frame.
  • offset_yaw: Hardware-derived orientation of the docking frame relative to the recorded contour, in radians.
  • pre_dock_dist: Distance of the second Nav2 pre-docking pose from the docking frame, in metres. It must be greater than zero.
  • approach_distance: Distance at which the node stops the normal approach and requests the APPROACHING safety mode, in metres. It must be greater than zero.
  • distance_tolerance: Non-negative tolerance added to approach_distance, in metres.
  • undock_dist: Distance travelled while reversing during undocking, in metres. It must be greater than zero.

Contour-matching parameters

  • initial_guess_x, initial_guess_y: Initial contour correction in the base_link frame, in metres.
  • initial_guess_yaw: Initial yaw correction in the base_link frame, in radians. Quaternion input is no longer required.
  • geometric_validation_enabled: Enables line and corner validation after GICP converges. Keep it enabled when the Wallbox is close to a wall to reject matches against surrounding wall geometry. It can be disabled for an isolated Wallbox after validating the installation.

For a robot that is always parked at approximately the same pose in front of the Wallbox, configure the initial correction directly in YAML:

neo_docking2:
  ros__parameters:
    initial_guess_x: 0.0
    initial_guess_y: -0.4
    initial_guess_yaw: 0.0
    geometric_validation_enabled: true

The configured initial guess is applied each time the user calls /perception/start_matching. Internal matching restarts during an active docking operation retain the last accepted contour pose instead.

Attention

offset_x, offset_y and offset_yaw are calculated from the hardware dimensions and vary with the ROX platform customization. Always begin with the platform-specific values supplied by Neobotix. Apply only small commissioning corrections after confirming that the hardware setup, scanner transform, contour detection and localization are correct. Contact the Neobotix support team if the calculated values are unavailable.

Why residual docking errors can remain

The calculated offsets describe the nominal rigid geometry of the robot and Wallbox. Small residual errors can remain on the installed system because of:

  • manufacturing and assembly tolerances in the robot, Wallbox and charging contacts;
  • scanner-bracket mounting tolerances or an inaccurate scanner transform;
  • laser range and angular resolution, surface reflectivity and the angle at which the Wallbox contour is observed;
  • discretization of the recorded contour and small GICP or line-fitting errors;
  • differences between the nominal base_link geometry and the physical chassis or contact position, including load-dependent chassis deflection;
  • map resolution, Nav2 goal tolerances or unstable localization during the pre-docking stages.

A small error that has approximately the same magnitude and direction over several tests can be treated as a commissioning calibration residual and corrected cautiously with offset_x or offset_y. An error that varies between attempts must not be tuned away with the offsets; investigate the scanner transform, contour detection, odometry, map and localization instead.

Tuning lateral docking alignment

Starting from the calculated platform value, if repeated docking tests still show a small, consistent lateral displacement in the same direction, fine-tune offset_y to shift docking_link laterally relative to the recorded Wallbox contour. This also shifts the second Nav2 pre-docking pose and the line followed by the final x-only controller.

A typical symptom is that the robot repeatedly stops at the transition to the final approach and cannot proceed into APPROACHING mode because Flexisoft does not recognize the expected Wallbox contour. If the scanner view is clear, the correct safety-field contour is configured and the failure is caused by a repeatable lateral displacement, fine-tuning offset_y can move the robot to the position at which the observed contour aligns with the contour expected by the APPROACHING safety field.

The lateral compensation can be measured mechanically using the two reference lines on the Wallbox and the corresponding two lines on the robot’s charging pad:

  1. Keep the robot stationary and move the Wallbox close to the charging pad.
  2. Make sure that the Wallbox and charging pad are parallel; otherwise, a yaw error will affect the lateral measurement.
  3. Align one Wallbox reference line with the corresponding line on the charging pad.
  4. Measure the lateral distance between the other pair of reference lines that remain unaligned. This distance is the magnitude of the required compensation.
  5. Apply the measured value to the calculated offset_y. Whether it must be added or subtracted depends on the direction of the docking frame’s y-axis.

Perform this measurement only during commissioning, with robot motion disabled, and secure the Wallbox in its intended operating position before testing.

After applying the measured compensation, validate it as follows:

  1. Confirm that the correct hardware-derived offset is configured, the scanner transform is correct, the map and localization are stable, and the lateral error is repeatable. Do not use offset_y to compensate for an error that changes between docking attempts.
  2. Inspect docking_link in RViz or measure the actual y-error in the docking frame. The difference between /docking_status and the final controller’s x-distance is not, by itself, a lateral-error measurement.
  3. Change offset_y in small increments, such as 0.01 metres. The required sign depends on the orientation of the docking frame’s y-axis.
  4. Repeat several docking tests and verify both the frame placement and the physical contact alignment before deployment.

initial_guess_y must not be used for this calibration. It provides an initial correction for contour matching, whereas offset_y defines the calibrated lateral placement of the docking target.

Tuning longitudinal docking distance

The hardware-derived offset_x establishes the nominal stopping position along the Wallbox approach axis. Starting from that value, if repeated tests show that the robot reaches or pushes against the Wallbox farther than intended, increase offset_x so that docking_link and the final stopping position are placed farther away from it. If the robot consistently stops too far away, offset_x can be decreased cautiously.

  1. Confirm that the offset matches the robot’s hardware configuration and that the scanner transform, contour and docking_link are correct in RViz before changing it.
  2. Change offset_x in small increments, such as 0.01 m.
  3. Repeat several low-speed docking tests after each change and verify the physical clearance or charging-contact engagement.
  4. Stop increasing or decreasing the offset when the required contact position is reached without the robot pressing against the Wallbox.

Only use offset_x for a consistent, repeatable longitudinal calibration error. A scanner stop, changing error between attempts or unstable localization must be diagnosed separately. initial_guess_x changes the contour-matching initial correction and must not be used to calibrate the stopping distance.

Available Services

  • /perception/start_matching (std_srvs/srv/Empty): Starts a new contour search using the YAML initial guess. It also clears a previously tracked match.
  • /perception/stop_matching (std_srvs/srv/Empty): Stops contour matching and invalidates the tracked match. /go_and_dock cannot be used again until matching has been started.
  • /perception/init_contour_pose (neo_srvs2/srv/InitializeContourMatching): Optionally updates the active x, y and yaw correction. The values are expressed in base_link and yaw is in radians.
  • /go_and_dock (std_srvs/srv/Empty): Starts docking only when contour matching is enabled and an accepted contour has produced a usable docking_link transform. The request is rejected or aborted if the required matching state or transforms are unavailable.
  • /undock_and_arm (std_srvs/srv/Empty): Starts undocking. After a successful undocking operation, matching is stopped and must be explicitly started before the next docking cycle.

Note

Service names are shown for the default node namespace. Add the robot namespace when neo_docking2 is launched in one.

Available Topics

  • /docking_status (neo_msgs2/msg/DockingStatus): Reports progress for both docking and undocking. The publisher uses reliable, transient-local QoS, so a late subscriber receives the most recently published status.
    • header: Timestamp and reference frame. The current implementation uses base_footprint.
    • distance_remaining: Remaining distance in metres. During docking it is derived from the base_footprint to docking_link transform. During undocking it decreases from undock_dist to zero. If the required transform is unavailable, the value can be NaN.
    • finished: true when the docking controller has finished processing the active docking or undocking operation; otherwise false. This does not confirm that the robot physically docked or undocked successfully. For example, the controller can finish after a timeout or scanner stop while distance_remaining is still nonzero. Applications must evaluate the remaining distance and, where applicable, the charging or contact state separately.

Monitor the status with:

ros2 topic echo /docking_status

Prerequisites

It is highly recommended to have the Wallbox mapped to prevent even minor localization jumps.

Launching the Docking Process

  1. Position the Robot

    Place the robot in front of the docking station so that its front laser scanners can view the entire contour.

  2. Start the Docking Package

    Attention

    Ensure that the robot is localized and the necessary navigation bring-up has been completed.

    ros2 launch neo_docking2 docking_launch.py
    
  3. Start Contour Matching

    Configure initial_guess_x, initial_guess_y and initial_guess_yaw for the expected parked pose, and then call:

    ros2 service call /perception/start_matching std_srvs/srv/Empty "{}"
    

    This service applies the YAML initial guess in base_link and starts a fresh search. If a different correction is needed for the current run, it can be supplied after starting matching:

    ros2 service call /perception/init_contour_pose \
      neo_srvs2/srv/InitializeContourMatching \
      "{x: 0.0, y: -0.4, yaw: 0.0}"
    
  4. Wait for an Accepted Contour

    Do not call /go_and_dock immediately after starting matching. Wait until the Wallbox contour has been accepted and docking_link is visible in TF. With geometric validation enabled, the node prints an Accepted contour geometry message. Use RViz to confirm that the detected contour and docking frame align with the physical Wallbox.

    If matching is stopped or no accepted docking transform is available, the robot does not begin docking.

  5. Initiate Docking

    Ensure that docking_link is correctly oriented as shown below before starting the docking process.

    ../_images/docking_start_pose.png
    ros2 service call /go_and_dock std_srvs/srv/Empty {}
    

    The docking sequence is:

    1. Nav2 moves the robot towards the first pre-docking pose calculated from the accepted contour.
    2. Contour matching runs again using the last accepted fixed-frame pose as its initial estimate, refining the Wallbox pose from the closer view.
    3. The refined docking pose is frozen in odom so that later map localization corrections cannot move the final target.
    4. Nav2 completes the pre-docking waypoints.
    5. The final controller drives only along the docking frame’s x-axis. Its remaining distance and stopping decision use odometry and the frozen docking target rather than the map frame.

    Note

    During the final approach, the robot can trigger a scanner stop. This is expected because the default NONE safety mode uses relatively long and wide safety fields. The docking node stops, requests the APPROACHING safety mode, waits for the transition, and then continues at controlled speed.

    Once docking is complete, the front frame of the robot will be approximately 1 cm from the charging station, with a deviation of ±0.5 cm.

    Charging can be started using the service provided by the neo_relayboardv3 node as follows:

    ros2 service call /start_charging std_srvs/srv/Empty {}
    
  6. Undocking

    Before undocking from the Wallbox it is essential to stop the charging process:

    ros2 service call /stop_charging std_srvs/srv/Empty {}
    

    Important

    Call the undocking service only while the robot is physically docked at the Wallbox. The safety scanners must have an unobstructed view of the Wallbox and must be able to recognize the Wallbox contour that was recorded and configured for the DEPARTING safety field. If the expected contour is not visible or does not match, the safety system can prevent the robot from moving and the undocking controller can finish after a timeout with a nonzero remaining distance.

    ros2 service call /undock_and_arm std_srvs/srv/Empty {}
    

    The robot moves away by the configured undock_dist. Monitor /docking_status if another component needs the remaining distance or completion state.

    Note

    During undocking, the node switches the Flexisoft safety mode to DEPARTING. After undocking, it restores NONE and stops contour matching. Call /perception/start_matching and wait for a newly accepted contour before beginning another docking cycle.

Stopping Matching Without Docking

To cancel perception before docking, call:

ros2 service call /perception/stop_matching std_srvs/srv/Empty "{}"

This invalidates the tracked contour and prevents a subsequent /go_and_dock request from starting until /perception/start_matching is called again and the Wallbox contour is accepted.

Safety Notes

Warning

The map must accurately represent a static environment, and localization must remain stable throughout both Nav2 pre-docking stages. A localization jump can cause Nav2 to finish with the robot laterally or angularly misaligned with the Wallbox. The final controller corrects only the docking-frame x-distance and cannot compensate for this misalignment, which may result in a scanner stop or incomplete docking. If localization becomes unstable, relocalize the robot and restart the docking sequence.

Warning

Keep the Wallbox stationary between contour acceptance and docking. The final target is deliberately frozen in odom after the second contour matching stage. Moving the Wallbox after that point can make the robot stop at the wrong physical position.

Warning

At least during initial testing, before deploying docking in an application, do not rely solely on GICP convergence. Verify the accepted docking_link pose in RViz, especially after changing scanner mounting, contour offsets or geometric-validation settings.