VEX V5 PYTHON | 10.3 SKILLS ROUTE SEQUENCES
Guide objective
Build a skills route from reusable movement, collection and release actions, checking prerequisites and sharing one route budget across the sequence.
01 | PLAN THE ROUTE BEFORE WRITING THE SEQUENCE
A skills route combines navigation, collection, mechanism positioning and scoring attempts. A long list of drive and motor commands becomes difficult to debug when every step assumes the previous one succeeded.
Build the route from checked actions. Each action has an entry condition, an observed completion rule, a time allowance and a failure policy.
Start with a short, repeatable route segment. Extend it after the robot demonstrates that segment reliably under the conditions discussed in 09.6.
02 | DRAW A ROUTE WITH CHECKPOINTS
Mark the starting pose, pickup areas, approach corridors and release stations in one coordinate frame. Include the robot footprint and mechanism clearance, not just a line through the centre.
Use the same +x, +y and clockwise-heading convention as section 07. Record a checkpoint where the robot can verify alignment or pause without obstructing its own next action.
The code below is game-independent and uses simulated travel and rotation. It does not prescribe field locations, object values or a competition time limit. Use the current game manual and measured field geometry when building an actual skills route.
03 | WRITE AN ACTION CONTRACT
| Action | Required entry evidence | Completion evidence | Failure policy |
|---|---|---|---|
| Navigate to pickup | Known start/pose, clear route, mechanisms in travel state | Position and heading tolerances with settling | Stop or validated fallback |
| Collect | Suitable pickup alignment and inventory capacity | Validated object-detection events | Timeout or bounded recovery |
| Approach release station | Inventory, clear route and suitable mechanism state | Verified station geometry and low motion | Stop; do not release blindly |
| Prepare mechanism | Travel limits, station clearance and settled chassis | Position/ready feedback | Stop with mechanism-specific cleanup |
| Release objects | Verified station, ready mechanism and inventory | Observed release events | Stop and record the incomplete attempt |
“Motor ran for one second” is a timed command outcome. “Two objects crossed an exit sensor” is release evidence. “Two objects legally scored” requires the current game criteria and appropriate observation.
04 | TRACK INVENTORY WITHOUT INVENTING CERTAINTY
Use validated sensor events to estimate how many objects are carried and released. Debounce or qualify entry/exit signals and rearm them after an object has cleared, as in 09.3.
A count can be wrong if objects overlap, move backwards or bypass the sensor. Keep an explicit unknown state when the evidence becomes unreliable. Do not convert unknown inventory to zero or assume collection succeeded after a timer expires.
The demonstration uses exact simulated counters so students can test sequencing. A physical implementation needs an object-counting policy and uncertainty handling suited to its mechanism.
05 | CHECK RELEASE PREREQUISITES AGAIN
Station verification must come from appropriate evidence and known geometry, not merely from completing a drive command. Review wall, tag and docking ideas from sections 08 and 09.
Before preparing or releasing, check station identity/geometry, heading, low measured motion, mechanism readiness and enough known inventory.
Continue checking required conditions while the release action runs. If alignment or readiness is lost, stop the normal sequence and record the reason. A one-time check can become stale.
06 | USE ONE SHARED TIME BUDGET
| Demonstration step | Action limit | Observed finish rule |
|---|---|---|
| Approach pickup: 300 mm | 6 s | Travel window and simulated low-rate settling |
| Collect two | 2 s | Simulated inventory at least two |
| Turn clockwise 90° | 3 s | Rotation window and low-rate settling |
| Approach station: 300 mm | 6 s | Travel window and low-rate settling |
| Verify station | 1 s | Station flag, heading and low motion |
| Prepare release | 1.5 s | Simulated mechanism ready |
| Release two | 2.5 s | Two simulated exit events |
Action allowances sum to more than the route budget. They are individual ceilings, not a promise that every action can consume its maximum.
Route acquisition, transitions, settling, retries and logging overhead consume the same overall allowance. Budget a measured finish margin. Use the actual period and conditions required by the current game, rather than copying the demonstration budget.
07 | COMPLETE NON-BLOCKING SEQUENCE DEMONSTRATION
Paste below # Begin project code, preserving generated VEX imports and Brain setup. Use a separate teaching project with no other movement code.
This is a software demonstration and commands no motors. Travel, rotation, inventory and mechanism response are idealised. station_verified is a deliberately fixed simulated external input, not wall recognition or localization.
Enter autonomous through the competition test setup to run the model. B, disable or a mode change cancels it. The completed event trace exports to the console after the project is disabled.
# =============================================================================
# TEAM [MY TEAM NAME / NUMBER] | SKILLS SEQUENCE SOFTWARE DEMONSTRATION
# =============================================================================
# Keep generated VEX imports and Brain setup above '# Begin project code'.
# No motor commands. Feedback and actuator responses below are simulated.
import math
controller = Controller(PRIMARY)
POLL_MS = 20
MAX_GAP_MS = 100
ROUTE_MS = 18000 # Teaching budget, not a declared competition period.
SETTLE_MS = 200
# Name, action kind, target, action timeout ms.
PLAN = (
('APPROACH_PICKUP','DRIVE',300.0,6000),
('COLLECT_TWO','COLLECT',2,2000),
('FACE_STATION','TURN',90.0,3000),
('APPROACH_STATION','DRIVE',300.0,6000),
('VERIFY_STATION','VERIFY',0,1000),
('PREPARE_RELEASE','PREPARE',0,1500),
('RELEASE_TWO','RELEASE',2,2500),
)
active = False
last_trace = []
exported_trace = None
run_number = 0
def zero_requests():
return {'drive':0.0,'turn':0.0,'intake':0.0,'release':0.0,'prepare':False}
class SimulatedRobot:
def __init__(self):
self.travel=0.0
self.rotation=0.0
self.objects=0
self.released=0
self.ready=False
self.collect_ms=self.release_ms=self.prepare_ms=0
# Explicit simulated external observation, NOT inferred from odometry.
self.station_verified=True
self.requests=zero_requests()
def snapshot(self):
return {'travel':self.travel,'rotation':self.rotation,'objects':self.objects,
'released':self.released,'ready':self.ready,
'station':self.station_verified,
'linear_rate':self.requests['drive']*10,
'angular_rate':self.requests['turn']*10}
def advance(self,dt_ms):
# Idealised model, without slip, inertia, collision or sensor delay.
self.travel+=self.requests['drive']*10*dt_ms/1000
self.rotation+=self.requests['turn']*10*dt_ms/1000
if self.requests['intake']>0:
self.collect_ms+=dt_ms
while self.collect_ms>=300 and self.objects<2:
self.collect_ms-=300
self.objects+=1
else:self.collect_ms=0
if self.requests['prepare']:
self.prepare_ms+=dt_ms
if self.prepare_ms>=400:self.ready=True
else:self.prepare_ms=0
if self.requests['release']>0 and self.ready and self.station_verified:
self.release_ms+=dt_ms
while self.release_ms>=350 and self.objects>0:
self.release_ms-=350
self.objects-=1
self.released+=1
else:self.release_ms=0
class StepAction:
def __init__(self,step,now,snapshot):
self.name,self.kind,self.target,self.limit=step
self.started=now
self.start=dict(snapshot)
self.settled_since=None
self.finished=None
self.reason=''
def fail(self,reason):
self.finished,self.reason='FAILED',reason
return 'FAILED',zero_requests(),reason
def done(self):
self.finished='DONE'
return 'DONE',zero_requests(),''
def update(self,now,s):
if self.finished is not None:return self.finished,zero_requests(),self.reason
if now-self.started>=self.limit:return self.fail('ACTION_TIMEOUT')
r=zero_requests()
if self.kind in ('DRIVE','TURN'):
key='travel' if self.kind=='DRIVE' else 'rotation'
error=self.start[key]+self.target-s[key]
tolerance=5 if self.kind=='DRIVE' else 2
rate=abs(s['linear_rate'] if self.kind=='DRIVE' else s['angular_rate'])
if self.kind=='DRIVE' and error < -tolerance:return self.fail('DRIVE_OVERSHOOT')
if abs(error)<=tolerance:
if rate<=1:
if self.settled_since is None:self.settled_since=now
if now-self.settled_since>=SETTLE_MS:return self.done()
else:self.settled_since=None
else:
self.settled_since=None
if self.kind=='DRIVE':r['drive']=max(0,min(20,.1*error))
else:r['turn']=max(-10,min(10,.7*error))
elif self.kind=='COLLECT':
if s['objects']>=self.target:return self.done()
r['intake']=20
elif self.kind=='VERIFY':
if (s['station'] and abs(s['rotation']-90)<=2
and abs(s['linear_rate'])<=1 and abs(s['angular_rate'])<=1):
return self.done()
# Stationary wait for evidence; never drive blindly to find it.
elif self.kind=='PREPARE':
if max(abs(s['linear_rate']),abs(s['angular_rate']))>1:
return self.fail('CHASSIS_NOT_SETTLED')
if not s['station']:return self.fail('STATION_LOST')
if abs(s['rotation']-90)>2:return self.fail('ALIGNMENT_LOST')
if s['ready']:return self.done()
r['prepare']=True
elif self.kind=='RELEASE':
if max(abs(s['linear_rate']),abs(s['angular_rate']))>1:
return self.fail('CHASSIS_NOT_SETTLED')
if not s['station'] or abs(s['rotation']-90)>2:
return self.fail('RELEASE_STATION_NOT_VERIFIED')
if not s['ready']:return self.fail('MECHANISM_NOT_READY')
released=s['released']-self.start['released']
if released>=self.target:return self.done()
if s['objects']<self.target-released:return self.fail('INSUFFICIENT_INVENTORY')
r['release']=20
else:return self.fail('UNKNOWN_ACTION')
return 'RUNNING',r,''
def valid_snapshot(s):
values=[s[k] for k in ('travel','rotation','objects','released','linear_rate','angular_rate')]
return (all(math.isfinite(v) for v in values)
and s['objects']>=0 and s['released']>=0
and int(s['objects'])==s['objects'] and int(s['released'])==s['released']
and isinstance(s['ready'],bool) and isinstance(s['station'],bool))
class SkillsSequence:
def __init__(self,now,snapshot):
self.deadline=now+ROUTE_MS
self.index=0
self.state='RUNNING'
self.reason=''
self.action=StepAction(PLAN[0],now,snapshot)
self.trace=[(now,'START',self.action.name,'')]
def fail(self,now,reason):
self.state,self.reason='FAULT',reason
self.trace.append((now,'FAULT',self.action.name,reason))
return zero_requests()
def tick(self,now,s):
if self.state!='RUNNING':return zero_requests()
if now>=self.deadline:return self.fail(now,'ROUTE_DEADLINE')
if not valid_snapshot(s):return self.fail(now,'INVALID_FEEDBACK')
status,requests,reason=self.action.update(now,s)
if status=='FAILED':return self.fail(now,self.action.name+':'+reason)
if status=='DONE':
self.trace.append((now,'STEP_DONE',self.action.name,''))
self.index+=1
if self.index==len(PLAN):
self.state='DONE_SEQUENCE'
self.trace.append((now,'RESULT','DONE_SEQUENCE','RELEASE_COUNT_NOT_LEGAL_SCORE'))
else:
self.action=StepAction(PLAN[self.index],now,s)
self.trace.append((now,'STEP_START',self.action.name,''))
return zero_requests() # New action first requests output next tick.
return requests
def cancelled():
return (not competition.is_enabled() or not competition.is_autonomous()
or controller.buttonB.pressing())
def run_demo():
global last_trace
robot=SimulatedRobot()
started=brain.timer.time(MSEC)
previous=started
machine=SkillsSequence(started,robot.snapshot())
result='EXCEPTION'
try:
while True:
now=brain.timer.time(MSEC)
if cancelled():result='CANCELLED';break
gap=now-previous
if gap>MAX_GAP_MS:result='UPDATE_GAP';break
if gap<0:result='CLOCK_FAULT';break
robot.advance(gap)
snapshot=robot.snapshot()
requests=machine.tick(now,snapshot)
commit=brain.timer.time(MSEC)
if cancelled():result='CANCELLED';break
if commit-previous>MAX_GAP_MS:result='UPDATE_GAP';break
if commit>=machine.deadline:result='ROUTE_DEADLINE';break
if (machine.state=='RUNNING'
and commit-machine.action.started>=machine.action.limit):
result='ACTION_DEADLINE_OVERRUN';break
# Real hardware needs feedback-age and API-duration checks too.
# Only a single guarded output owner may commit these requests.
robot.requests=requests # Simulated request commit, not motor output.
previous=commit
if machine.state!='RUNNING':result=machine.state+': '+machine.reason;break
wait(POLL_MS,MSEC)
except Exception:
result='EXCEPTION'
finally:
robot.requests=zero_requests()
machine.trace.append((brain.timer.time(MSEC),'EXIT',machine.action.name,result))
last_trace=[(t-started,event,step,reason) for t,event,step,reason in machine.trace]
return result
def autonomous():
global active,run_number
if active or (last_trace and last_trace is not exported_trace):return
active=True
run_number+=1
try:
run_demo() # No console printing during the demonstration.
finally:
active=False
def driver_control():
pass # No driver or motor output in this standalone demonstration.
competition=Competition(driver_control,autonomous)
while True:
if not competition.is_enabled() and not active and last_trace is not exported_trace:
exported_trace=last_trace
if exported_trace:
print('run_id,elapsed_ms,event,step,reason')
for t,event,step,reason in exported_trace:
if competition.is_enabled():
exported_trace=None
break
print(str(run_number)+','+str(t)+','+event+','+step+','+reason)
wait(100,MSEC)
The engine creates each action once on entry, updates it promptly, and applies zero requests on every transition. A required failure prevents all later normal actions.
DONE_SEQUENCE means the model completed its action contracts. Released objects are not counted as legally scored points. The trace explicitly records this limitation.
08 | CONNECT TESTED HARDWARE ACTIONS
Retain the route plan and sequencing interface, then replace the simulated adapter with your existing validated actions. Use motion functions from sections 05–07, mechanism protection from 05.5 and 05.6, and verified alignment from section 08.
# Real action adapter contract: # start(now, snapshot): capture entry targets once # update(now, snapshot): return RUNNING/DONE/FAILED, requests, reason # requests: sent only through one guarded output owner # cancel(reason): revoke the action and apply resource-specific cleanup
A physical drive adapter needs appropriate pose/heading feedback, speed limits and settling. A collection/release adapter needs validated object feedback. A lift adapter needs calibration, travel limits and a suitable holding or stop policy.
Carry the 09.4 cancellation and watchdog checks around feedback acquisition and output calls. Recheck action and route deadlines before committing output. Sequential API calls are not atomic, and same-loop checks cannot preempt a permanently blocked API call.
09 | OVERLAP ONLY INDEPENDENT ACTIONS
Running intake while navigating can save time, provided the collection path, power demand and resource ownership allow it. Moving a lift while turning may introduce instability or clearance problems.
Use the resource and join policies from 09.2. Complete required prerequisites before releasing objects, even if other actions were allowed to overlap earlier.
The demonstration is deliberately sequential. Do not create separate threads that fight over motors when adding overlap. Define which action owns each resource and how required failures cancel the group.
10 | RECOVER FROM A CHECKPOINT, NOT A GUESS
A recovery requires known conditions: a validated checkpoint, usable pose estimate, appropriate inventory and sufficient remaining time.
Examples include one bounded re-alignment attempt at a verified station, or a tested alternative route when an approach is unavailable. Do not reverse blindly or repeat a release after unknown feedback.
The starter fails and ends the sequence. It implements no automatic retries or fallback motion. Add recovery only with an explicit retry limit and the original shared route deadline.
11 | TEST SMALL SEGMENTS, THEN THE WHOLE ROUTE
- Validate each movement and mechanism action alone.
- Test a pickup segment and compare counted inventory with physical inspection.
- Test station verification without releasing objects.
- Test a conservative release attempt and compare exit evidence with the actual outcome.
- Inject missing inventory, lost alignment, unavailable feedback and timeouts in simulation.
- Test cancellation during each action and verify cleanup.
- Combine segments and measure complete-route duration.
- Repeat with realistic battery, temperature, surface and load conditions.
Use telemetry from 10.2 to record action starts, finish evidence, elapsed time and failure reasons. Keep external outcome records alongside internal controller status.
12 | CHOOSE VALUE USING REPEATABILITY
The shortest path or largest theoretical score is not always the best skills plan. Compare achievable outcomes, time, reliability and recovery cost.
For a simple illustration, an isolated action worth V points with success probability p has expected contribution p × V if failure contributes zero. Whole-route actions are often dependent, and one failure can prevent later attempts, so do not simply add independent estimates without checking those assumptions.
Use the next guide, 10.4, to evaluate repeated trials and success rates. Retain failures and partial outcomes in the data rather than reporting only the best run.
13 | COMMON MISTAKES
- Assuming a drive finish proves a scoring position: verify the station.
- Calling a timed release a legal score: label the observed outcome accurately.
- Recreating actions every tick: capture targets and deadlines once.
- Releasing with unknown inventory: establish usable object evidence.
- Continuing after a required failure: prevent later normal actions.
- Giving recovery a fresh full budget: retain the route deadline.
- Overlapping incompatible mechanisms: check stability, clearance and ownership.
- Testing only the complete route: isolate segments and prerequisites.
CHALLENGES | PLAN, SEQUENCE AND VERIFY
- Contract: document entry and finish evidence for each action in your route.
- Trace: identify the first action created after each completion event.
- Inventory: simulate a collection failure and show that release never begins.
- Station: make the simulated station flag False during release and inspect the failure.
- Deadline: shorten the shared budget and verify later actions are prevented.
- Cancel: interrupt each stage and verify all requests end at zero.
- Integrate: connect one validated movement or mechanism adapter.
- Evaluate: compare release evidence, legal scoring outcome and complete-route success over repeated trials.
Success evidence
A route map, action-contract table, inventory/verification policy, stage traces, failure and cancellation tests, plus independent physical outcome measurements.
OFFICIAL REFERENCES
The sequence engine and software model are independently written teaching examples. Confirm current rules and physically validate your real route and action adapters.