Chapter 28
The throttle
The rider is always choosing whether to accelerate, brake or hold steady. The Throttle module returns that choice once a step, as an acceleration.
ThrottleThe rider has several reasons to slow down, and each is a rule of its own. A bend is coming. A cat is in the lane. There's a pig to look at. Coasting on would carry the bike off the road. Throttle writes them as a list of limits, the chain in the second diagram. It starts from offered, the cruise acceleration. fold hands each limit in turn to held_to, with the acceleration so far, and each limit lets it through or lowers it:
# ...
limits = [
bend_limit(motorcycle, segment),
EncounterReaction.encounter_throttle(segment.encounter, encounter_stage),
Gawking.gawk_brake(motorcycle, segment),
shoulder_limit(motorcycle),
]
limits.fold(offered, held_to)
# ...
Call this the chain of limits. Each limit reads alone, and a new reason to slow down is one more line in the list.
Each limit is a ThrottleLimit: NoLimit, or AtMost some acceleration. held_to takes the lower:
## Nothing, or to accelerate no harder than this.
ThrottleLimit := [NoLimit, AtMost(Acceleration)].{
is_eq : _
}
## The acceleration `a`, held to what `limit` asks.
held_to : Acceleration, ThrottleLimit -> Acceleration
held_to = |a, limit|
match limit {
AtMost(most) => a.min(most)
NoLimit => a
}
The throttle returns an acceleration, and the motorcycle's step turns it into a speed.
Speed and Acceleration are a pair like the clock and its steps: a speed is a value, and an acceleration is the change from one speed to another. To brake for a bend, the rider needs the steady acceleration that takes its speed to a target within so much road. That's Speed.acceleration_to. Its within is a Distance: the road the change has to happen in. The formula is the first line of a physics textbook, v² = u² + 2ad, solved for a, with the speed going from s to t over the distance within. In the parameter list, Speed.(s) and target: Speed.(t) unwrap the two speeds into plain numbers, as Clock.(n) does in the “Opaque types: the clock” chapter:
## The steady acceleration that brings this speed to `target` within this
## distance.
acceleration_to : Speed, { target : Speed, within : Distance } -> Acceleration
acceleration_to = |Speed.(s), { target: Speed.(t), within }|
Acceleration.metres_a_step_each_step((t * t - s * s) / (2.0 * within.to_metres()))
It has one caller, VehicleLimits.braking_to. That function also holds the speed steady when at most a micrometre of road is left, and enforces the invariant that every speed is zero or more, with a crash. The rider's bend brake, the gawk brake and the truck all brake through braking_to. The first limit is the bend's:
## Near the end of the segment, the brake that brings the rider to the exit
## speed at the point where they commit to the turn. Past that point there is
## no road left to brake on, and the limit holds the acceleration at none.
bend_limit : Motorcycle, Segment -> ThrottleLimit
bend_limit = |motorcycle, segment| {
rider_along = motorcycle.route_place.road_point.along
if is_near_end(rider_along, segment.length) {
segment_exit_speed = exit_speed(segment)
room_to_commit = segment.commit_along().distance_from(rider_along)
AtMost(
VehicleLimits.braking_to(
motorcycle.speed,
{ target: segment_exit_speed, within: room_to_commit },
),
)
} else {
NoLimit
}
}
exit_speed is the speed the bend ahead allows, or rest on the route's last segment, so the same limit brings the rider to a stop at the end of the road.
The last limit, shoulder_limit, comes back in the “Variables and loops: rehearsal” chapter, because it runs a pretend copy of the bike forward, which is what that chapter is about. The two in the middle come from what the rider sees: encounter_throttle is the cat's, and gawk_brake the pig's. The cat's comes in the “What a cat does to the rider” chapter, and the pig's comes after Rehearsal, in the “The rider's gaze” chapter.