Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Actuated controls #295

Closed
khuston opened this issue Aug 25, 2020 · 5 comments
Closed

Actuated controls #295

khuston opened this issue Aug 25, 2020 · 5 comments

Comments

@khuston
Copy link
Contributor

khuston commented Aug 25, 2020

I've written up what I have in mind from #266 in a little more detail.

a lot of behavior could be captured by including features found here like (1) skipping phases that aren't called, (2) making artificial calls to "recall" preferred phases every cycle, (3) specifying parameters like minimum green interval, maximum green interval, passage time gap before terminating a phase.

The goal is to replicate the behavior shown in this diagram from the source linked above:
5_2A

The parameters are:

  1. Minimum green (following start of green)
  2. Maximum green (following first actuation of conflicting phase)
  3. Passage time gap (following most recent actuation on current phase)
  4. Walk time (following start of green)
  5. Crosswalk clearance time (following end of walk)

These timers would presumably be implemented by scheduling an UpdateIntersection command for when the actuation or signal change occurs, plus the duration of the timer.

Example 1: When a car actuates the active turn group at time t, the Control is updated by setting the most recent passage time to now, and an UpdateIntersection is scheduled for t + passage_time_gap. When that command occurs, if the most recent passage time is still t, and the same phase is still green, then the green light will "gap out" or expire.

Example 2: When a car actuates an inactive turn group at time t, if the Control's Maximum Green timer has not already started, an UpdateIntersection is scheduled for t + maximum_green. When that command occurs, if the same phase is still green, then the green light will expire.

The internal state of the control can be represented approximately as in the following diagram, with the addition of some reference times to check whether to proceed to another state when updating.

controller_state_diagram

What will be covered

How a vehicle call is determined
Only turns which are not included in the following phase will be counted as calls for the current phase. Why, you ask? So a vehicle intending to drive straight does not activate or prolong a phase that includes a left turn, which is followed by a straight-only phase.

Pedestrian calls
Since uncalled phases can be skipped, pedestrians need to be able to call an uncalled phase. If a pedestrian requests to cross, a cross will be recorded for that crosswalk. When the next phase is not called by vehicular traffic, it will be called by the pedestrian unless there is another phase in the cycle that can service these pedestrian calls and one or more other pedestrian calls.

What will not be covered (yet)

Partial yellow
When the current phase's green is ending, if the next phase is called and it shares one or more protected turns, those turns do not need to yellow. This would be nice to have, but it is not a priority for this work.

Localized/lane-specific sensing
Calls for phases will be made based on vehicle intent (i.e. turn group), not the presence of any sensors.

Phase generation
Although I would like to keep interesting phases in mind

Multi-signal coordination
With variable-length greens, some extra behavior would be needed to ensure signals remain synchronized for each cycle.

Implementation details

  • I haven't figured out yet where/how to define actuation, i.e. the place in code where the signal is actuated. I can figure something if I investigate a while longer, but do you have an idea @dabreegster ? Is there an event/command when a vehicle reaches the end of a lane?
  • I'd like to keep the interface to actuate a control as simple as possible, with just the current time, the turn group, and the scheduler. (I need to see what the equivalent of turn group would be for pedestrians)
@dabreegster
Copy link
Collaborator

This write-up is excellent, thanks for the detail/clarity balance!

Is there an event/command when a vehicle reaches the end of a lane?

maybe_start_turn is called. This can actually get called multiple times for a single car waiting at one intersection; wakeup_waiting will indirectly trigger that. You can dedupe by seeing checking waiting: BTreeMap<Request, Time>.

I need to see what the equivalent of turn group would be for pedestrians

TurnGroupID has a crosswalk bit. The many different crosswalks and directions for them are a little confusing; let me know if https://github.com/dabreegster/seattle_traffic_signals/blob/master/crosswalk_turns.png doesn't clarify. Note that one physical crosswalk has two turn groups associated, for each direction across the crosswalk.

Implementation notes:

  • Feel free to split out a new module and call it from mechanics/intersection.rs if you prefer, since that code is already quite complex.
  • Likewise, current_phase and phase_ends_at are awkwardly wedged into State. It might be nicer to replace these with traffic_signal_state: Option<YourStateStruct>
  • The industry standard terminology confusingly overlaps with what abst uses. I have Rename traffic signal "phase" #197 filed to rename "phase" to "stage". I can make this change tonight if it would help. (If "stage" isn't standard and you know a better term, open to suggestions!)
  • IIUC, a "phase" in MUTCD-land is a turn group in abst. So in the UI, we need a way to edit all of these parameters per turn group, correct?
  • I recently added backwards compatibility support for serialized map edits, including traffic signals. I think there'll be some work here to support this. If it's easier for you, you can skip over some of the import/export logic in traffic_signals.rs and I can fill this in.

@khuston
Copy link
Contributor Author

khuston commented Aug 25, 2020

Thanks for the quick feedback.

About "phase" and "stage", what you've said makes sense. I don't have enough subject matter knowledge to know what a better term would be.

Rushing #197 isn't necessary. I'm new to these terms anyway, so I can keep thinking about "phases" and "turn groups" until after the work is done, and then start thinking about "stages" and "phases".

IIUC, a "phase" in MUTCD-land is a turn group in abst. So in the UI, we need a way to edit all of these parameters per turn group, correct?

I was using "phase" in the abstreet sense, so the parameters would be per intersection stage, or they could be global/map-level and overridden per intersection stage. It's a lot easier for me to think about separate, non-overlapping stages with mostly independent behavior right now. (The only inter-stage behavior being that a green phase will stay green instead of yellowing when the next called stage also has that phase)

If it turns out that to really model signal controls well, we need per-phase parameters, then we would need a more sophisticated control mechanism than the one I have in mind.

@dabreegster
Copy link
Collaborator

the parameters would be per intersection stage

Ah great, I was worried we'd need to come up with a new UI scheme to select a turn group and modify a whole bunch of parameters. We're on the same page here. :)

I'll try to respond to questions here as fast as possible, but also feel free to join our Slack if that's easier

@khuston
Copy link
Contributor Author

khuston commented Aug 28, 2020

(I’m using the phase/stage terms here rather than turn group/phase)

My plan of preferring a later stage to service a phase was short-sighted:

  • For leading left turns, it is reasonable, because a straight-bound car doesn’t prolong the left.
  • For lagging left turns, it is wrong, because a straight-bound car will inadvertently call the lagging left stage!

When we get to parameter optimization of the traffic signals, we could do something interesting like map a phase’s calls to the stage which has the highest traffic volume.

In the meantime I’ll use a simple heuristic like assigning straight turn calls to the compatible stage with the most straight turns. Or maybe I’ll just greedily pick the current/next compatible stage until we get around to optimization.

Edit: On further reflection, I am trying to solve a problem that doesn't need to be solved. Unless I'm missing one, none of the stages we have today have the same phase in consecutive stages (except for crosswalks).

The reason I started thinking about this phase -> stage mapping problem at all was in figuring out how to support leading/lagging lefts that are timed independently from the straights they can overlap with. I was trying to shoehorn this kind of operation into the existing mode where a phase is either on or off for the entire duration of a stage. But real controllers don't require that - phases can turn on and off within a single stage. And because of this, there's no need to create stages with the same phase consecutively in order to fake leading/lagging lefts. It could be accomplished with two stages as below.

ordered-phases-separated-by-stage

In this operation, stages still don't overlap, but one phase can give way to another. Having done a little more research into how traffic signals are programmed, it seems this phase-timing approach with stages acting as barriers between phases is more in line with the way most traffic controls in the U.S. work. That said, I would guess there a lot of stage-timing controls as well, but the stage-timing behavior can be achieved with the phase-timing control.

The biggest differences from today are:

  1. Parameters can be set per phase rather than stage (but they don't have to be, so the UI change isn't needed right away)
  2. The sequence of phases within a stage is important if there are conflicting phases within a stage. In the drawing above, for example, each one of the left turns conflicts with a later straightaway.

The last thing I'll point out is that although I didn't put crosswalks in the drawing, they easily fit into each stage as additional phases that are blocked by a left turn.

The control flow each time the signal is updated would look something like below. (abstreet doesn't have red lights, so that part of the activity diagram would be simplified)

phase-based control flow

dabreegster pushed a commit that referenced this issue Dec 24, 2020
* Add a Variable phase

Variable provides a min duration, a delay duration, and an additional duration. The maximum cycle time is min + additional. Once min has been exhausted, if there is demand, the cycle is extended by delay until there isn't any demand or the additional duration has been consumed.

#295
dabreegster added a commit that referenced this issue Jan 4, 2021
…this a long time ago. #295

Make this schema change backwards compatible for player edits.
@dabreegster
Copy link
Collaborator

I'm closing this issue, since @BruceBrown has implemented variable stages that pretty much capture all of this behavior. But @khuston I really appreciate the clear write-up and flowcharts about how to reason about this. Please reopen if there's any future work you have in mind.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants