Skip to content

Simulation

coordination_oru.simulation2D.trajectory_envelope_coordinator_simulation

TrajectoryEnvelopeCoordinatorSimulation: simulated-robot fleet coordinator.

Ported from Java's TrajectoryEnvelopeCoordinatorSimulation. Wires up TrajectoryEnvelopeTrackerRK4 as the tracker factory, provides sane default footprint/kinodynamic parameters for robots that don't configure their own, and mirrors getCurrentTimeInMillis() off the wall clock.

DEFAULT_FOOTPRINT = ((-1.7, 0.7), (-1.7, -0.7), (2.7, -0.7), (2.7, 0.7)) module-attribute

AbstractTrajectoryEnvelopeTracker

Bases: ABC

te = te instance-attribute

traj = te.getTrajectory() instance-attribute

temporalResolution = temporalResolution instance-attribute

externalCPCounter = -1 instance-attribute

reportCounter = -1 instance-attribute

criticalPoint = -1 instance-attribute

trackingPeriodInMillis = trackingPeriodInMillis instance-attribute

cb = cb instance-attribute

tec = tec instance-attribute

startingTimeInMillis = tec.getCurrentTimeInMillis() instance-attribute

getTrackingPeriod()

getStartingTimeInMillis()

resetStartingTimeInMillis()

onTrajectoryEnvelopeUpdate() abstractmethod

updateTrajectoryEnvelope(te)

setCanStartTracking()

canStartTracking()

waitUntilCanStartTracking() async

setCriticalPoint(criticalPoint) abstractmethod

setCriticalPointWithCounter(criticalPointToSet, externalCPCounter)

setReportCounter(reportCounter)

getReportCounter()

getCriticalPoint()

getTrackingPeriodInMillis()

getLastRobotReport()

getRobotReport() abstractmethod

onPositionUpdate()

getCurrentTimeInMillis() abstractmethod

startTracking() abstractmethod

trackingStarted()

getTrajectoryEnvelope()

finishTracking()

cancel()

CollisionEvent dataclass

timestamp instance-attribute

robot_report_1 instance-attribute

robot_report_2 instance-attribute

ConstantAccelerationForwardModel

Bases: ForwardModel

maxAccel = maxAccel instance-attribute

maxVel = maxVel instance-attribute

temporalResolution = temporalResolution instance-attribute

controlPeriodInMillis = controlPeriodInMillis instance-attribute

trackingPeriodInMillis = trackingPeriodInMillis instance-attribute

canStop(te, currentState, targetPathIndex, useVelocity)

getEarliestStoppingPathIndex(te, currentState)

Mission

robotID = robotID instance-attribute

path = tuple(path) instance-attribute

order = next(_mission_order_counter) instance-attribute

fromLocation = fromLocation if fromLocation is not None else str(self.path[0].getPose()) instance-attribute

toLocation = toLocation if toLocation is not None else str(self.path[-1].getPose()) instance-attribute

fromPose = fromPose if fromPose is not None else self.path[0].getPose() instance-attribute

toPose = toPose if toPose is not None else self.path[-1].getPose() instance-attribute

stoppingPoints = [] instance-attribute

stoppingPointDurations = [] instance-attribute

compareTo(other)

setStoppingPoint(pose, duration)

clearStoppingPoints()

getStoppingPoints()

setToLocation(location)

setFromLocation(location)

getRobotID()

getPath()

setPath(path)

getFromLocation()

getToLocation()

getFromPose()

setFromPose(fromPose)

getToPose()

setToPose(toPose)

TrajectoryEnvelopeTrackerRK4

Bases: AbstractTrajectoryEnvelopeTracker

MAX_VELOCITY = maxVelocity instance-attribute

MAX_ACCELERATION = maxAcceleration instance-attribute

state = State(0.0, 0.0) instance-attribute

setUseInternalCriticalPoints(value)

getCurvatureDampening(index, backwards)

onTrajectoryEnvelopeUpdate()

startTracking()

setCriticalPoint(criticalPointToSet)

setCriticalPointWithCounter(criticalPointToSet, externalCPCounter)

getRobotReport()

getCurrentTimeInMillis()

TrajectoryEnvelopeCoordinator

Bases: AbstractTrajectoryEnvelopeCoordinator

currentOrdersGraph = nx.DiGraph() instance-attribute

currentCyclesList = {} instance-attribute

replanningStoppingPoints = {} instance-attribute

breakDeadlocksByReordering = True instance-attribute

breakDeadlocksByReplanning = True instance-attribute

avoidDeadlockGlobally = False instance-attribute

nonliveStatesDetected = 0 instance-attribute

nonliveStatesAvoided = 0 instance-attribute

currentOrdersHeurusticallyDecided = 0 instance-attribute

nonliveCyclesOld = [] instance-attribute

replanningTrialsCounter = 0 instance-attribute

successfulReplanningTrialsCounter = 0 instance-attribute

forceCriticalPointReTransmission = {} instance-attribute

staticReplan = False instance-attribute

isBlocked = False instance-attribute

isDeadlockedFlag = False instance-attribute

deadlockedCycles = [] instance-attribute

deadlockedCallback = None instance-attribute

replanFailedCallback = None instance-attribute

fake = False instance-attribute

isBlockedFleet()

setBreakDeadlocks(global_, reorder, replan)

setDeadlockedCallback(cb)

setReplanFailedCallback(cb)

Called from :meth:rePlanPath — after the replanningStoppingPoints pins are popped — when no robot in the set could be replanned, with the robotsToReplan set. Lets the deployment decide what to do with an unresolvable deadlock (e.g. cancel the missions and park the robots). Not called when the replan task is cancelled.

setStaticReplan(value)

setFakeCoordination(fake)

depsToGraph(deps)

nonlivePair(dep1, dep2)

findSimpleNonliveCycles(g)

computeClosestDependencies(allDeps, artificialDeps)

computeIsDeadlocked()

Recompute :attr:isDeadlockedFlag without firing the deadlocked callback — safe for observers (e.g. viewers) to poll. Also records :attr:deadlockedCycles: every nonlive cycle whose robots have all come to rest at their communicated critical points ([] when none has).

isDeadlocked()

findAndRepairNonliveCycles(currentDeps, artificialDeps, reversibleDeps, currentReports)

callLocalReordering(nonlive_cycles, artificialDeps, g, reversibleDeps, allDeps, currentReports)

replanEnvelope(robotID, onlyIfDeadlocks=False)

callOnePathReplan(cycle, g)

spawnReplanning(robotsToReplan, allConnectedRobots)

stopInference() async

setMaxCPDependencies(robotIDs)

rePlanPath(robotsToReplan, robotsAsObstacles) async

Three-phase lock scope per robot: gather dep/pose/obstacle info under self._lock, run the (possibly slow, possibly remote) plan with the lock released — the involved robots stay pinned via replanningStoppingPoints — and re-acquire only for the replacePath commit.

replacePath(robotID, newPath, breakingPathIndex, lockedRobotIDs, concatenatePaths=True)

truncateEnvelope(robotID)

truncateEnvelopeAt(robotID, pathIndex)

reverseEnvelope(robotID)

getOrder(robotTracker1, robotReport1, robotTracker2, robotReport2, cs)

updateDependencies()

localCheckAndRevise()

sendCriticalPoint(robotID, currentReports)

cleanUpRobotCS(robotID, lastWaitingPoint)

deleteEdge(edge)

deleteEdges(edgesToDelete)

addEdges(edgesToAdd)

updateGraph(edgesToDelete, edgesToAdd)

globalCheckAndRevise()

TrajectoryEnvelope dataclass

A robot's planned trajectory expressed as an STP-aware swept envelope.

envelope_id is assigned by the :class:~coordination_oru.metacsp.spatial.trajectory_envelope_solver.TrajectoryEnvelopeSolver that creates it; start_node / end_node are the STP variable indices for this envelope's start and end times.

envelope_id instance-attribute

robot_id instance-attribute

path instance-attribute

start_node instance-attribute

end_node instance-attribute

spatial_envelope instance-attribute

footprint instance-attribute

component = 'Driving' class-attribute instance-attribute

nominal_duration = 0.0 class-attribute instance-attribute

completed = False class-attribute instance-attribute

metadata = field(default_factory=dict) class-attribute instance-attribute

length property

pose_at(index)

waypoint_footprint(index)

getID()

getRobotID()

getPathLength()

getSpatialEnvelope()

getFootprint()

getTrajectory()

makeFootprint(ps)

getComponent()

getSequenceNumberStart()

getSequenceNumberEnd()

getSequenceNumber(x, y)

Index of the path point closest to (x, y).

Mirrors Java's getSequenceNumber(Coordinate) used to locate stopping points along the path.

TrackingCallback

myTE = te instance-attribute

updateTrajectoryEnvelope(te)

beforeTrackingStart()

onTrackingStart()

onNewGroundEnvelope()

beforeTrackingFinished()

onTrackingFinished()

onPositionUpdate()

TrajectoryEnvelopeCoordinatorSimulation

Bases: TrajectoryEnvelopeCoordinator

DEFAULT_ROBOT_TRACKING_PERIOD = DEFAULT_ROBOT_TRACKING_PERIOD instance-attribute

DEFAULT_MAX_VELOCITY = MAX_VELOCITY instance-attribute

DEFAULT_MAX_ACCELERATION = MAX_ACCELERATION instance-attribute

useInternalCPs = True instance-attribute

checkCollisions = False instance-attribute

collisionsList = [] instance-attribute

totalMsgsLost = 0 instance-attribute

totalPacketsLost = 0 instance-attribute

DEFAULT_FOOTPRINT = Polygon(DEFAULT_FOOTPRINT) instance-attribute

MAX_DEFAULT_FOOTPRINT_DIMENSION = self.computeMaxFootprintDimension(DEFAULT_FOOTPRINT) instance-attribute

setCheckCollisions(enable)

incrementLostMsgsCounter()

incrementLostPacketsCounter()

setUseInternalCriticalPoints(value)

getRobotMaxVelocity(robotID)

getRobotMaxAcceleration(robotID)

getMaxFootprintDimension(robotID)

getDefaultFootprint()

getFootprint(robotID)

setDefaultFootprint(*coordinates)

getNewTracker(te, cb)

getCurrentTimeInMillis()

addMissions(*missions)

onCriticalSectionUpdate()

_compute_stopping_points(poses)

coordination_oru.simulation2D.trajectory_envelope_tracker_rk4

TrajectoryEnvelopeTrackerRK4: simulated robot tracked via RK4 integration.

Ported from Java's TrajectoryEnvelopeTrackerRK4. Simplifications versus the Java original (documented, not silently dropped):

  • No simulated network delay/packet loss on reports (getLastRobotReport always returns the freshest report) — :mod:coordination_oru.network_configuration defaults to zero delay/loss, so this only changes behaviour if a caller deliberately configures nonzero values, which this port does not yet wire up for the report path.
  • No ground-envelope / sub-envelope deadline bookkeeping (see :mod:coordination_oru.abstract_trajectory_envelope_tracker).

The kinodynamic core — computeDistance, integrateRK4, the slow-down profile, setCriticalPoint honouring the critical point by decelerating to a stop at it — is a faithful numeric port.

log = get_logger(__name__) module-attribute

WAIT_AMOUNT_AT_END_MILLIS = 3000 module-attribute

EPSILON = 0.01 module-attribute

AbstractTrajectoryEnvelopeTracker

Bases: ABC

te = te instance-attribute

traj = te.getTrajectory() instance-attribute

temporalResolution = temporalResolution instance-attribute

externalCPCounter = -1 instance-attribute

reportCounter = -1 instance-attribute

criticalPoint = -1 instance-attribute

trackingPeriodInMillis = trackingPeriodInMillis instance-attribute

cb = cb instance-attribute

tec = tec instance-attribute

startingTimeInMillis = tec.getCurrentTimeInMillis() instance-attribute

getTrackingPeriod()

getStartingTimeInMillis()

resetStartingTimeInMillis()

onTrajectoryEnvelopeUpdate() abstractmethod

updateTrajectoryEnvelope(te)

setCanStartTracking()

canStartTracking()

waitUntilCanStartTracking() async

setCriticalPoint(criticalPoint) abstractmethod

setCriticalPointWithCounter(criticalPointToSet, externalCPCounter)

setReportCounter(reportCounter)

getReportCounter()

getCriticalPoint()

getTrackingPeriodInMillis()

getLastRobotReport()

getRobotReport() abstractmethod

onPositionUpdate()

getCurrentTimeInMillis() abstractmethod

startTracking() abstractmethod

trackingStarted()

getTrajectoryEnvelope()

finishTracking()

cancel()

Pose dataclass

x instance-attribute

y instance-attribute

theta instance-attribute

z = math.nan class-attribute instance-attribute

roll = math.nan class-attribute instance-attribute

pitch = math.nan class-attribute instance-attribute

is_3d()

distance_xy(other)

getX()

getY()

getTheta()

distanceTo(other)

interpolate(other, ratio)

Linear interpolation towards other; theta via shortest arc.

Trajectory

getPoseSteering()

getPose()

RobotReport

robotID = robotID instance-attribute

pose = pose instance-attribute

pathIndex = pathIndex instance-attribute

velocity = velocity instance-attribute

distanceTraveled = distanceTraveled instance-attribute

criticalPoint = criticalPoint instance-attribute

getRobotID()

getPose()

getPathIndex()

getVelocity()

getDistanceTraveled()

getCriticalPoint()

Derivative

velocity = velocity instance-attribute

acceleration = acceleration instance-attribute

getVelocity()

getAcceleration()

evaluate(initial_state, time, delta_time, deriv, slow_down, max_velocity, max_velocity_dampening_factor, max_acceleration) staticmethod

compute_acceleration(state, time, slow_down, max_velocity, max_velocity_dampening_factor, max_acceleration) staticmethod

State

position = distance instance-attribute

velocity = velocity instance-attribute

getPosition()

setPosition(distance)

getVelocity()

setVelocity(velocity)

clone()

TrackingCallback

myTE = te instance-attribute

updateTrajectoryEnvelope(te)

beforeTrackingStart()

onTrackingStart()

onNewGroundEnvelope()

beforeTrackingFinished()

onTrackingFinished()

onPositionUpdate()

AbstractTrajectoryEnvelopeCoordinator

Bases: ABC

CONTROL_PERIOD = CONTROL_PERIOD instance-attribute

TEMPORAL_RESOLUTION = TEMPORAL_RESOLUTION instance-attribute

DEFAULT_ROBOT_TRACKING_PERIOD = DEFAULT_ROBOT_TRACKING_PERIOD instance-attribute

overlay = False instance-attribute

quiet = False instance-attribute

totalMsgsSent = 0 instance-attribute

totalMsgsReTx = 0 instance-attribute

criticalSectionCounter = 0 instance-attribute

solver = None instance-attribute

missionsPool = [] instance-attribute

envelopesToTrack = [] instance-attribute

currentParkingEnvelopes = [] instance-attribute

allCriticalSections = set() instance-attribute

CSToDepsOrder = {} instance-attribute

depsToCS = {} instance-attribute

escapingCSToWaitingRobotIDandCP = {} instance-attribute

stoppingPoints = {} instance-attribute

stoppingTimes = {} instance-attribute

stoppingPointTimers = {} instance-attribute

trackers = {} instance-attribute

currentDependencies = {} instance-attribute

communicatedCPs = {} instance-attribute

externalCPCounters = {} instance-attribute

comparators = [] instance-attribute

forwardModels = {} instance-attribute

footprints = {} instance-attribute

maxFootprintDimensions = {} instance-attribute

robotTrackingPeriodInMillis = {} instance-attribute

robotMaxVelocity = {} instance-attribute

robotMaxAcceleration = {} instance-attribute

muted = set() instance-attribute

yieldIfParking = True instance-attribute

checkEscapePoses = True instance-attribute

trackingCallbacks = {} instance-attribute

inferenceCallback = None instance-attribute

motionPlanners = {} instance-attribute

packetLossProbability = network_configuration.PROBABILITY_OF_PACKET_LOSS instance-attribute

MAX_TX_DELAY = network_configuration.getMaximumTxDelay() instance-attribute

maxFaultsProbability = network_configuration.PROBABILITY_OF_PACKET_LOSS instance-attribute

numberOfReplicas = 1 instance-attribute

isDriving = {} instance-attribute

criticalPointSafetyMargin = 0.0 instance-attribute

getMaxFootprintDimension(robotID)

getFootprint(robotID)

getFootprintPolygon(robotID)

setFootprint(robotID, *coordinates)

computeMaxFootprintDimension(coords)

setForwardModel(robotID, fm)

getForwardModel(robotID)

setRobotTrackingPeriodInMillis(robotID, trackingPeriodInMillis)

getRobotTrackingPeriodInMillis(robotID)

setCriticalPointSafetyMargin(margin)

Stop yielding robots at least margin metres of arc length (along their own path) before the first conflicting pose of a critical section, in addition to the classic TRAILING_PATH_POINTS backoff. 0.0 (the default) preserves the original behaviour exactly.

setRobotMaxVelocity(robotID, maxVelocity)

setRobotMaxAcceleration(robotID, maxAcceleration)

getRobotMaxVelocity(robotID)

getRobotMaxAcceleration(robotID)

setNetworkParameters(packetLossProbability, max_tx_delay, maxFaultsProbability)

setInferenceCallback(cb)

getControlPeriod()

getTemporalResolution()

setYieldIfParking(value)

setCheckEscapePoses(value)

toggleMute(robotID)

mute(robotID)

unMute(robotID)

getMuted()

getCurrentTimeInMillis() abstractmethod

setupSolver(max_envelopes=64)

startInference() async

stopInference() async

isStartedInference()

onNewMissionDispatched(robotID)

onCriticalSectionUpdate()

getDrivingEnvelopes()

isParked(robotID)

isDrivingRobot(robotID)

getIdleRobots()

getAllRobotIDs()

getRobotReport(robotID)

getCurrentDependencies()

getCurrentSuperEnvelope(robotID)

getCurrentTrajectoryEnvelope(robotID)

addTrackingCallback(robotID, cb)

setVisualization(viz)

addComparator(c)

setMotionPlanner(robotID, mp)

getMotionPlanner(robotID)

inParkingPose(robotID)

setCriticalPoint(robotID, criticalPoint, retransmitt)

placeRobot(robotID, currentPose=None, parking=None, location=None)

isFree(robotID)

atStoppingPoint(robotID)

spawnWaitingThread(robotID, index, duration)

getObstaclesInCriticalPoints(robotIDs)

getObstaclesFromWaitingRobots(robotID)

makeObstacles(robotID, *obstaclePoses)

doReplanning(mp, fromPose, toPose, obstaclesToConsider=()) async

Plan off the event loop: mp.plan() may take seconds (or, for a remote planner, must itself wait on messages delivered by this very loop), so the whole motion-planner interaction runs in a worker thread.

updateDependencies() abstractmethod

canExitCriticalSection(drivingCurrentIndex, waitingCurrentIndex, drivingTE, waitingTE, lastIndexOfCSDriving)

getCriticalPoint(yieldingRobotID, cs, leadingRobotCurrentPathIndex)

isAhead(cs, rr1, rr2)

computeCriticalSections()

filterCriticalSections()

getCriticalSections(te1, minStart1, te2, minStart2, checkEscapePoses, maxDimensionOfSmallestRobot) staticmethod

cleanUpRobotCS(robotID, lastWaitingPoint)

cleanUp(te)

Retire an envelope no longer in use — ports Java's cleanUp (solver.removeConstraints + solver.removeVariable, verified against the real org.metacsp.framework.ConstraintSolver / ConstraintNetwork source). Java's network is a sparse graph (removeVariable deletes the vertex outright; memory is bounded by live entries alone); this port's TrajectoryEnvelopeSolver instead uses a dense STP distance matrix sized for the whole process's variable count, so the equivalent fix (TrajectoryEnvelopeSolver.mark_completed) both excludes the envelope from solver.envelopes() — the active set computeCriticalSections considers, so a retired envelope can't spuriously conflict with robots long gone from that space — and detaches its two STP variables, freeing their matrix slots for reuse so the working set stays bounded by concurrently-active envelopes rather than growing for the coordinator's entire lifetime. Also drops it from currentParkingEnvelopes if present.

cleanUpStaleParkingEnvelope(robotID)

A robot's parking envelope from before its current mission stays in currentParkingEnvelopes until that mission finishes through the normal onTrackingFinished path (which retires it there) — a caller that ends a mission a different way (e.g. recovery's hard-drop cancel) must retire it here instead, or it leaks for the coordinator's remaining lifetime.

startTrackingAddedMissions()

addMissions(*missions)

getNewTracker(te, cb) abstractmethod

TrajectoryEnvelope dataclass

A robot's planned trajectory expressed as an STP-aware swept envelope.

envelope_id is assigned by the :class:~coordination_oru.metacsp.spatial.trajectory_envelope_solver.TrajectoryEnvelopeSolver that creates it; start_node / end_node are the STP variable indices for this envelope's start and end times.

envelope_id instance-attribute

robot_id instance-attribute

path instance-attribute

start_node instance-attribute

end_node instance-attribute

spatial_envelope instance-attribute

footprint instance-attribute

component = 'Driving' class-attribute instance-attribute

nominal_duration = 0.0 class-attribute instance-attribute

completed = False class-attribute instance-attribute

metadata = field(default_factory=dict) class-attribute instance-attribute

length property

pose_at(index)

waypoint_footprint(index)

getID()

getRobotID()

getPathLength()

getSpatialEnvelope()

getFootprint()

getTrajectory()

makeFootprint(ps)

getComponent()

getSequenceNumberStart()

getSequenceNumberEnd()

getSequenceNumber(x, y)

Index of the path point closest to (x, y).

Mirrors Java's getSequenceNumber(Coordinate) used to locate stopping points along the path.

TrajectoryEnvelopeTrackerRK4

Bases: AbstractTrajectoryEnvelopeTracker

MAX_VELOCITY = maxVelocity instance-attribute

MAX_ACCELERATION = maxAcceleration instance-attribute

state = State(0.0, 0.0) instance-attribute

setUseInternalCriticalPoints(value)

getCurvatureDampening(index, backwards)

onTrajectoryEnvelopeUpdate()

startTracking()

setCriticalPoint(criticalPointToSet)

setCriticalPointWithCounter(criticalPointToSet, externalCPCounter)

getRobotReport()

getCurrentTimeInMillis()

get_logger(name=None, **bindings)

A lazy proxy, not a materialized logger: don't call .bind() here.

BoundLoggerLazyProxy.bind() immediately freezes in whatever structlog.configure() last set (processors, wrapper class, logger factory) onto a concrete BoundLogger. Every call site does log = get_logger(__name__) at module import time, which for downstream consumers happens before their own structlog.configure() runs — eagerly binding would permanently lock these loggers onto structlog's unconfigured defaults (console-only, print-based), deaf to any later reconfiguration. structlog.get_logger(name, **bindings) passes bindings through as initial context instead, keeping the proxy lazy so it materializes against whatever config is active at first log call.

computeDistance(traj, startIndex, endIndex)

integrateRK4(state, time_, deltaTime, slowDown, MAX_VELOCITY, MAX_VELOCITY_DAMPENING_FACTOR, MAX_ACCELERATION)

_robot_report_at(traj, aux_state, robot_id, critical_point)

coordination_oru.simulation2D.state

State: 1-D arclength position/velocity pair used by the RK4 integrator.

State

position = distance instance-attribute

velocity = velocity instance-attribute

getPosition()

setPosition(distance)

getVelocity()

setVelocity(velocity)

clone()

coordination_oru.simulation2D.derivative

Derivative: (velocity, acceleration) pair for RK4 integration steps.

EPSILON = 0.0001 module-attribute

State

position = distance instance-attribute

velocity = velocity instance-attribute

getPosition()

setPosition(distance)

getVelocity()

setVelocity(velocity)

clone()

Derivative

velocity = velocity instance-attribute

acceleration = acceleration instance-attribute

getVelocity()

getAcceleration()

evaluate(initial_state, time, delta_time, deriv, slow_down, max_velocity, max_velocity_dampening_factor, max_acceleration) staticmethod

compute_acceleration(state, time, slow_down, max_velocity, max_velocity_dampening_factor, max_acceleration) staticmethod