unused, WIP code for peds to wait for, board, deboard buses

This commit is contained in:
Dustin Carlino 2018-08-30 16:40:10 -07:00
parent c38c9d43ac
commit c1f87395cc
7 changed files with 152 additions and 11 deletions

View File

@ -480,6 +480,12 @@ How to share common state in intersections?
- have one struct that then contains an enum
- when delegating to specialized thing, can pass this unpacked thing down, right?
Seeing lots of deadlock bugs from accepting non-leader vehicles. For now,
switch to only considering leader vehicles, and later maybe relax to anybody
following only accepted vehicles.
Leader vehicle is a bit vague; could be leader on current queue, which is still a bit far away.
## Notes on determinism ##
- serde tricks
@ -576,14 +582,6 @@ around the precomputed front of the spot, used for drawing and for cars to line
up their front in the sim. I think we need to plumb the true start of the spot
and have a method to interpolate and pick the true front.
## Intersection protocol
Seeing lots of deadlock bugs from accepting non-leader vehicles. For now,
switch to only considering leader vehicles, and later maybe relax to anybody
following only accepted vehicles.
Leader vehicle is a bit vague; could be leader on current queue, which is still a bit far away.
## Trips
Time to get even more multi-modal / multi-phase!
@ -658,8 +656,14 @@ for now, since pathfinding ignores live traffic, probably fine to ignore this.
- step 3: make peds load on the bus and get off at the correct stop. make buses usually wait a fixed time at each stop, but wait a littl extra if loading passengers takes a while.
- should walking state own peds waiting for a bus?
- yes: easier drawing, later need to know how crowded a sidewalk is, it's just weird to keep indicating we're at a place. router for cars does this, and the transit sim holds the higher-level state. do the same for now.
- kind of want walking sim to have a list of peds idling at bus stops. transit sim can let all of them know when a bus arrives!
- no: transit sim can also contribute DrawPeds. the walking layer has nothing left to do with them... right?
so:
1) ped reaches bus stop, writes event. walking sim flips a bit so they stop trying to step(). also has a multimap of bus stop -> waiting peds. they continue to exist on their sidewalk for rendering / crowding purposes.
2) transit sim gets a step(). for every bus that's waiting, it queries walking sim to see what peds are there. ??? trip thingy will decide if the ped takes the bus or not, but the ownership transfer of ped from walking to transit happens then.
3) when a bus initially arrives at a stop, it queries all passengers to see who wants to get off and join the walking sim again. the trip thingy decides that.
- step N: load in GTFS for seattle to get real routes and stops
later: multiple transfers, dedicated bus lanes, light rail...
@ -678,6 +682,43 @@ Driving and walking layer are both kind of broken, since they know about
parking spots and bus stops. Feels like they need to be dumb, mechanical layers
that're guided by higher-level behaviors, which understand trips and such.
Could be simpler to flatten. Call each sim and dont affect other sims, then
process all events last to do transitions. except maybe one sim expects the
transition to happen immediately, so have to process events between each one?
Just to kind of document the dependency/call-chain right now...
- sim step
- TODO spawner step
- driving step
- router
- transit.get_action_when_stopped_at_end
- this changes bus state (wouldnt it be nicer to
- foreach parked car as a result, add to parking sim and tell spawner that car reached spot
ask: a way to statically or at runtime print the call-chain, stopping at std libs?
- whenever we push onto events, dump stack?
for each api method in each sim, manually look at its call chain
- transit
- create_empty_route, get_route_starts, bus_created
- spawn.seed_bus_route
- sim.seed_bus_route
- get_action_when_stopped_at_end (changes bus state, returns new path), get_dist_to_stop_at
- router.react_before_lookahead
- driving per car react
- driving step
- step (lots of state transitions happen here, but call stack is simple!)
- walking
- ped_joined_bus
- transit.step
A good measue of how well-structured the code is: how hard would it be to add a
few more delays / states, like time after parking the car (out of the way of
the driving sim) but before getting out of the car?
## Routers, lookahead, cars as FSMs
Hmm, hard to figure out the interactions for the router. when should it get a

View File

@ -7,7 +7,9 @@ OSM, elevation data, King Country GIS data, etc, and also manual edits.
- Polygons shouldn't overlap
- Can export to various formats and announce for anyone's use (though waiting for the editor might be wiser)
- Have fun with themed rendering: halloween, winter, jungle, 8bit, organic (deform buildings), floorplan
- Have fun with themed rendering: halloween, winter, jungle, 8bit, organic
(deform buildings), floorplan, machine (make buildings pump along front
paths)
## Phase 2: Editor

View File

@ -5,6 +5,7 @@ use geom::{Angle, Line, PolyLine, Pt2D};
use std;
use std::f64;
use std::fmt;
use std::hash::{Hash, Hasher};
use {BuildingID, IntersectionID, RoadID};
pub const PARKING_SPOT_LENGTH: si::Meter<f64> = si::Meter {
@ -31,6 +32,7 @@ pub enum LaneType {
Biking,
}
// TODO This should be a lightweight, copyable, hashable address, like ParkingSpot
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct BusStop {
pub sidewalk: LaneID,
@ -47,6 +49,16 @@ impl PartialEq for BusStop {
impl Eq for BusStop {}
impl Hash for BusStop {
fn hash<H: Hasher>(&self, state: &mut H) {
self.sidewalk.hash(state);
self.driving_lane.hash(state);
// TODO sadface. bus stops for a particular sidewalk won't be crowded, so 1m granularity is
// fine here.
(self.dist_along.value_unsafe as usize).hash(state);
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Lane {
pub id: LaneID,

View File

@ -14,6 +14,9 @@ pub enum Event {
BusDepartedFromStop(CarID, BusStop),
PedReachedBuilding(PedestrianID, BuildingID),
PedReachedBusStop(PedestrianID, BusStop),
PedEntersBus(PedestrianID, CarID),
PedLeavesBus(PedestrianID, CarID),
// TODO split up into cases or not?
AgentEntersTraversable(AgentID, On),

View File

@ -250,6 +250,9 @@ impl Sim {
.ped_reached_parking_spot(self.time, ped, spot, &self.parking_state);
}
self.transit_state
.step(&mut events, &mut self.walking_state);
// TODO want to pass self as a lazy QueryCar trait, but intersection_state is mutably
// borrowed :(
let mut info = AgentInfo {

View File

@ -4,6 +4,7 @@ use events::Event;
use map_model;
use map_model::{BusStop, LaneID, Map};
use std::collections::{BTreeMap, VecDeque};
use walking::WalkingSimState;
use {CarID, Distance, PedestrianID, RouteID, Tick};
type StopIdx = usize;
@ -178,4 +179,41 @@ impl TransitSimState {
}
}
}
pub fn step(&mut self, events: &mut Vec<Event>, walking_sim: &mut WalkingSimState) {
for b in self.buses.values_mut() {
if let BusState::AtStop(stop_idx, _) = b.state {
let stop = self.routes[&b.route].stops[stop_idx].clone();
// Let anybody new on?
for p in walking_sim.get_peds_waiting_at_stop(&stop).into_iter() {
println!("TODO should {} board bus {}?", p, b.car);
if true {
events.push(Event::PedEntersBus(p, b.car));
b.passengers.push(p);
walking_sim.ped_joined_bus(p, &stop);
}
}
// Let anybody off?
// TODO ideally dont even ask if they just got on, but the trip planner things
// should be fine with this
// TODO only do this if we JUST arrived at the stop, and in fact, wait for everyone
// to leave, since it may take time.
// so actually, we shouldnt statechange mutably in get_action_when_stopped_at_end,
// which is called by router! thats convoluted
let car = b.car;
b.passengers.retain(|p| {
println!("TODO should {} leave bus {}?", p, car);
if false {
events.push(Event::PedLeavesBus(*p, car));
// TODO call something on the spawner to join the walking sim again
false
} else {
true
}
});
}
}
}
}

View File

@ -4,7 +4,7 @@ use dimensioned::si;
use draw_ped::DrawPedestrian;
use geom::Pt2D;
use intersections::{AgentInfo, IntersectionSimState, Request};
use map_model::{BuildingID, Lane, LaneID, Map, Turn, TurnID};
use map_model::{BuildingID, BusStop, Lane, LaneID, Map, Turn, TurnID};
use multimap::MultiMap;
use parking::ParkingSimState;
use std;
@ -56,6 +56,14 @@ impl SidewalkSpot {
dist_along: front_path.dist_along_sidewalk,
}
}
pub fn bus_stop(stop: BusStop) -> SidewalkSpot {
SidewalkSpot {
sidewalk: stop.sidewalk,
dist_along: stop.dist_along,
connection: SidewalkPOI::BusStop(stop),
}
}
}
// Point of interest, that is
@ -63,6 +71,7 @@ impl SidewalkSpot {
enum SidewalkPOI {
ParkingSpot(ParkingSpot),
Building(BuildingID),
BusStop(BusStop),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@ -75,6 +84,7 @@ struct CrossingFrontPath {
enum Action {
StartParkedCar(ParkingSpot),
WaitAtBusStop(BusStop),
StartCrossingPath(BuildingID),
KeepCrossingPath,
Continue,
@ -97,6 +107,9 @@ struct Pedestrian {
front_path: Option<CrossingFrontPath>,
goal: SidewalkSpot,
// If false, don't react() and step(). Waiting for a bus.
active: bool,
}
// TODO this is used for verifying sim state determinism, so it should actually check everything.
@ -131,6 +144,7 @@ impl Pedestrian {
return match self.goal.connection {
SidewalkPOI::ParkingSpot(spot) => Action::StartParkedCar(spot),
SidewalkPOI::Building(id) => Action::StartCrossingPath(id),
SidewalkPOI::BusStop(ref stop) => Action::WaitAtBusStop(stop.clone()),
};
}
return Action::Continue;
@ -285,6 +299,9 @@ pub struct WalkingSimState {
#[serde(serialize_with = "serialize_multimap")]
#[serde(deserialize_with = "deserialize_multimap")]
peds_per_turn: MultiMap<TurnID, PedestrianID>,
#[serde(serialize_with = "serialize_multimap")]
#[serde(deserialize_with = "deserialize_multimap")]
peds_per_bus_stop: MultiMap<BusStop, PedestrianID>,
}
impl WalkingSimState {
@ -293,6 +310,7 @@ impl WalkingSimState {
peds: BTreeMap::new(),
peds_per_sidewalk: MultiMap::new(),
peds_per_turn: MultiMap::new(),
peds_per_bus_stop: MultiMap::new(),
}
}
@ -323,8 +341,10 @@ impl WalkingSimState {
// Could be concurrent, since this is deterministic.
let mut requested_moves: Vec<(PedestrianID, Action)> = Vec::new();
for p in self.peds.values() {
if p.active {
requested_moves.push((p.id, p.react(map, intersections)));
}
}
// In AORTA, there was a split here -- react vs step phase. We're still following the same
// thing, but it might be slightly more clear to express it differently?
@ -343,6 +363,11 @@ impl WalkingSimState {
self.peds.remove(&id);
}
}
Action::WaitAtBusStop(ref stop) => {
self.peds.get_mut(&id).unwrap().active = false;
events.push(Event::PedReachedBusStop(*id, stop.clone()));
self.peds_per_bus_stop.insert(stop.clone(), *id);
}
Action::StartParkedCar(ref spot) => {
self.peds.remove(&id);
results.push((*id, *spot));
@ -469,6 +494,7 @@ impl WalkingSimState {
waiting_for: None,
front_path,
goal,
active: true,
},
);
self.peds_per_sidewalk.insert(start_lane, id);
@ -510,6 +536,22 @@ impl WalkingSimState {
.get(&id)
.map(|p| p.path.iter().map(|id| *id).collect())
}
pub fn get_peds_waiting_at_stop(&self, stop: &BusStop) -> Vec<PedestrianID> {
// TODO ew, annoying multimap API and clone
self.peds_per_bus_stop
.get_vec(stop)
.unwrap_or(&Vec::new())
.clone()
}
pub fn ped_joined_bus(&mut self, id: PedestrianID, stop: &BusStop) {
self.peds.remove(&id);
self.peds_per_bus_stop
.get_vec_mut(stop)
.unwrap()
.retain(|&p| p != id);
}
}
fn is_contraflow(map: &Map, from: LaneID, to: LaneID) -> bool {