Add GoToZone feature#516
Open
chart-singapore wants to merge 2 commits into
Open
Conversation
Co-authored-by: Loke Ji Xian <loke_ji_xian@cgh.com.sg> Co-authored-by: Tey Leong Teck <leong_teck_tey@cgh.com.sg> Signed-off-by: Loke Ji Xian <loke_ji_xian@cgh.com.sg> Signed-off-by: Tey Leong Teck <leong_teck_tey@cgh.com.sg> Signed-off-by: kjchee <keai_jiang_chee@cgh.com.sg>
Open
19 tasks
Signed-off-by: kjchee <keai_jiang_chee@cgh.com.sg>
This was referenced Apr 22, 2026
2 tasks
Collaborator
|
Hi @mxgrey, noting down our planned responses to your comments from yesterday's Interoperability Meeting. Comment 1: Remove the same-vertex entry/exit lane restriction
Comment 2: Remove the zone guard model
Comment 3: Opt-in / opt-out of zone stubbornness
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
New feature implementation
Implemented feature
This is the main PR for GoToZone Feature. Tracked in Stage A of open-rmf/rmf#726.
Introduces GoToZone task/event (input a zone name instead of a waypoint) & a zone booking system that lets robots claim, hold, and release specific waypoints inside named zones (e.g., consultation rooms, parking zone, ward bedside parking) under the arbitration of a new standalone Zone Supervisor node. Fleet adapters interact with the zone supervisor via new
rmf_zone_msgstopics, and zone entry/exit (request booking/release booking) are wired into the plan execution pipeline via nav-graph lane events.This PR is the deep-dive for an 8-repo feature.
rmf_internal_msgsrmf_zone_msgspackage (7 msgs)rmf_building_map_msgsGraphZone,ZoneVertex,ZoneTransitionLanermf_trafficrmf_traffic_editorrmf_taskGoToZonetask-sequence event +ZoneGuardModelrmf_ros2(this)rmf_visualizationrmf_demosdispatch_zone.pyMerge sequence: 1 --> 2 --> 3 --> 4.
Implementation description
A. Overview: End-to-end flow
1. Dispatch. A user submits a zone task either as a top-level task (
category: "zone") or as aGoToZoneevent nested inside a larger task sequence. The request may carry optionalmodifiers.waypoint_preferencehints that influence waypoint selection inside the zone:group— a label the user assigns to subsets of zone vertices in the Traffic Editor (e.g.left,right,center). The supervisor prefers candidates in the matching group.orientation— the robot's desired heading (radians) at the final selected waypoint.preferred_waypoints— an ordered list of candidate waypoint names; each entry may be the fully qualified vertex name (e.g.consultation#R#p1#wait_2) or the short alias (wait_2) shown in Traffic Editor / RViz.Future stages will extend this list with sensor-driven options.
2. Deserialization. The JSON request is validated and deserialized into a
GoToZone::Descriptionbyrmf_fleet_adapter/src/rmf_fleet_adapter/tasks/Zone.cpp, producing an event-sequence description for the task planner.3. Bidding (
ZoneGuardModel). During task bidding, the task planner callsZoneGuardModel::estimate_finishfor each candidate robot. If a robot's current waypoint is already one of the zone's internal waypoints,estimate_finishreturnsstd::nulloptand that robot is excluded from bidding on this particular zone task (while remaining eligible for other tasks). This prevents awarding a zone task to a robot that is already parked inside the zone.4. Execution entry. When a robot wins the bid, its
TaskManagerdispatches the task and invokes the execution logic atrmf_fleet_adapter/src/rmf_fleet_adapter/events/GoToZone.cpp.GoToZone::Active:is_zone_task = trueand records the caller's modifiers on theRobotContext.robot_task_requestassignments that bypass bidding.GoToPlace::Activebuilt fromGoToPlace::Description::make_for_one_of(goals).wrapped_finishedcallback so that on completion/cancel/kill,is_zone_task,zone_task_modifiers, andbooked_zone_goalare all cleared on theRobotContext.5. Initial planning. Inside
GoToPlace, the planner selects the lowest-cost goal from the list (initially any internal vertex in the zone) and produces a plan toward it.6. Zone entry — booking handshake. When the plan routes the robot onto a lane whose
entry_eventisZoneEntry(wired byparse_graph.cppfrom the nav graph's transition-lane metadata),ExecutePlaninserts aZoneEntryphase. The phase:ZoneRequestof typeENTRYonzone_requests, stamped with a freshrequest_idof the form{fleet}_{robot}_{zone}_{random_hex}.zone_states(transient-local QoS) and waits for aZoneBookingwhoserequest_idmatches exactly.set_booked_zone_goal(...)andset_booked_zone_waypoint(...)on theRobotContext, then invokesrequest_replan().7. Replan to the assigned waypoint. On replan,
GoToPlace::_find_plan()readsbooked_zone_goalfrom theRobotContextand uses it as the planner goal in place of "any of the internal vertices". The robot now heads to the specific waypoint the supervisor assigned.8. In-zone operation. The robot parks at the assigned waypoint.
_booked_zone_waypointremains set, holding an RAII_zone_stubbornnessreference that prevents traffic negotiators from displacing the robot while it is occupying its booked slot.9. Zone exit — release. When a subsequent task (for example, a
GoToPlaceto a waypoint outside the zone) routes the robot onto a lane whoseexit_eventisZoneExit,ExecutePlaninserts aZoneExitphase. The phase publishes aZoneRequestof typeEXIT, awaits release confirmation from the zone supervisor, then clearsbooked_zone_waypointon theRobotContext. The stubbornness reference drops.10. Recovery paths. Two out-of-band mechanisms handle bookings that are not released cleanly by the normal flow:
ZoneManualReleasemessage to the supervisor with the affected(robot, fleet, zone)triple, then zone supervisor drops the booking and publishes aZoneBookingRevokedmessage so the affectedRobotContextcan clean up its zone-state fields.stale_booking_check_interval = 60 s) that compares each booked robot's reported position against the x/y of its booked waypoint. A booking that previously latchedhas_arrivedand is now out of tolerance is marked as suspect. If the suspect state persists forstale_booking_grace_period(default 180 s), the supervisor revokes the booking and publishes aZoneBookingRevokedto the affected robot.B. New task type (
zone) and new event type (go_to_zone)Two JSON schemas define the external surface:
schemas/task_description__zone.json— the top-levelcategory: "zone"task. Dispatch withdispatch_task_request.schemas/event_description__zone.json— thego_to_zoneevent for use inside a composed task sequence.C. New fleet-adapter event:
events/GoToZoneThe event-level handler for
go_to_zone. Responsibilities:GoToPlace::Activethat targets all internal vertices of the named zone as amake_for_one_ofgoal set.RobotContext: setsis_zone_task = trueand records the caller'szone_task_modifiers.wrapped_finishedcallback that clears task-level zone state (is_zone_task,zone_task_modifiers,booked_zone_goal) on completion / cancel / kill, preventing state leakage into the next task._booked_zone_waypointis intentionally not cleared here, it stays set until the robot physically leaves the zone (viaZoneExitor forcedZoneBookingRevoked), so that the stubbornness guard remains in force for the whole in-zone period.D. New phases:
ZoneEntryandZoneExitImplemented as legacy-style task phases (via
LegacyPhaseShim), consistent with existing low-level phases such asDoorOpenandRequestLift. They are inserted byExecutePlanwhen the robot traverses a lane whoseentry_event/exit_eventcarries aZoneEntryorZoneExit— wired at nav-graph parse time inparse_graph.cpp.ZoneEntrypublishes anENTRYZoneRequestto the zone supervisor, waits for a matchingZoneBooking, stores the assigned waypoint and planner goal on theRobotContext, then callsrequest_replan()so that the outerGoToPlace(insideevents/GoToZone) routes the robot to the granted waypoint.ZoneExitpublishes anEXITZoneRequestto the zone supervisor, waits for release confirmation, then clears the booking on theRobotContext.Open question for reviewers. These phases follow the older
LegacyPhaseShimpattern. We are happy to migrate them to the newer event-based framework used byLockMutexGroupif Open-RMF maintainers prefer that direction.E. New node:
zone_supervisorA standalone ROS 2 node that owns zone-booking authority. All callbacks share a single
MutuallyExclusivecallback group, so_zone_log,_zones, and the derived indexes are accessed without additional locks.Responsibilities:
ZoneRequest(ENTRY/EXIT) and allocates waypoints through a 4-stage algorithm:group_hintis set and matches any candidate, narrow to that subset, otherwise keep all candidates.preferred_waypointsis set, return the first one present in the current candidate set.priorityvalue.ZoneStatesnapshots on state change (event-driven).has_arrivedlatch that prevents false revocations while the robot is still in transit.ZoneManualReleasefor operator-initiated recovery (e.g. a broken-down robot that needs to be manually pulled out of a zone).Tunable parameters:
stale_booking_check_interval(default 60 s)stale_booking_distance_threshold(default 1.0 m)stale_booking_grace_period(default 180 s)F.
RobotContextnew fields_is_zone_taskboolExecutePlanto decide whether aZoneEntryphase should be inserted when the plan crosses a zone entry lane._zone_task_modifiersZoneTaskModifiersstructgroup_hint,orientation_hint,preferred_waypoints) carried from the task description into theZoneRequestpayload._booked_zone_goalstd::optional<Plan::Goal>GoToPlace::_find_plan()when non-empty. Cleared when theGoToZonetask completes / cancels / kills._booked_zone_waypointstd::stringZoneExit) or the booking is revoked. Also gates_zone_stubbornness._zone_stubbornnessstd::shared_ptr<void>_booked_zone_waypointis set, released when cleared.G. Known limitations
No transit-zone support. If a user dispatches a plain
GoToPlacewhose planned path happens to pass through a zone, noZoneEntry/ZoneExitevents fire — zones are only honored when the task / event is explicitlyGoToZone. Transit-zone handling is deferred to a later stage (lift cabin zone and lift waiting zone).ZoneExitonly fires on zone exit-lane traversal. If a subsequent plan starts inside the zone but the startset resolves to a waypoint outside the zone (an edge case where the robot's startset has already merged onto an external waypoint), the exit lane is never traversed and the booking is not released through the normal path. But the zone supervisor's periodic stale-booking check (default every 60 s) will eventually remove such bookings.Direct
GoToPlaceto a zone internal vertex is soft-blocked, not hard-blocked. Zone internal vertices are exposed in RViz / Traffic Editor only by their "short name" (e.g.wait_2), the fully qualified form (consultation#R#p1#wait_2) thatGoToPlacewould need to resolve is intentionally hidden. This discourages, but does not prevent, a user from dispatchingGoToPlacedirectly to a zone waypoint — which would bypass the supervisor and leave the zone in an inconsistent state.GenAI Use
We follow OSRA's policy on GenAI tools