Inspiration
Every day in Cascais I saw Bird scooters lying in the middle of the pavement, far from any station. In this challenge I learned that there are two sides to this problem. Bird is a private company: it earns money from rides and must keep its scooters at stations. Cascais Próxima works for the city: if a scooter stays more than 30 m from a station for more than 2 hours, the city removes it with its own van, and Bird pays a €4.5 fine.
When I looked at the data, the problem was bigger than I expected: about 44 new abandoned scooters every day, and a typical one stays on the street for more than 15 hours. The city team had no tool to decide which scooters to collect first or which way to drive. I wanted to build that tool.
What it does
Cascais Sweep has three steps.
1. Detect. It finds abandoned scooters in 3 weeks of history or in Bird's live public feed (GBFS), updated every minute.
2. Prioritise. Every scooter gets a score:
$$ \text{score} = 3\,T + 2\,D + 1.5\,(1 - P) + 1.5\,S $$
where \(T\) is the time abandoned (\(\frac{\text{hours}}{12}\), max 1), \(D\) is the distance from a station (\(\frac{\text{metres}}{300}\), max 1), \(S\) is 1 when the scooter blocks a bus stop, and \(P\) is the chance that a rider takes it anyway, from a logistic regression model (65% accuracy vs 57% baseline). The weights are sliders, so the city decides.
3. Route. The tool chooses the scooters worth the most per minute of driving, within 18 places and the time available, and gets the order and the path on real streets from OSRM.
The website also shows supply and demand per area (H3 hexagons) and the impact: on 3 weeks of real data, +27% scooters in the same 2-hour run, and 59% less time abandoned with a full shift.
How I built it
- Python (pandas, geopandas, shapely, h3, scikit-learn) for the analysis: I cut every scooter's events into "parking" periods and checked if each one was outside the 30 m zone for more than 2 hours.
- A small collector saves Bird's GBFS feed every minute, and
live_map.pyturns these snapshots into live data for the website. - The website uses plain HTML, CSS and JavaScript with Leaflet and OpenStreetMap, and OSRM for routing. Everything is open source, with no API keys.
- I talked to João Silva from Cascais Próxima to check the rules: the depot, the van size, how the team works and the fine.
- I used an AI assistant (Claude) as a tutor: it explained libraries I did not know and helped me find bugs. I rewrote the website myself step by step, so I understand how every part works.
Challenges I ran into
- Bird changes the scooter ID on every request. To follow a scooter in time, I had to match scooters between snapshots by position: exact coordinates first (about 95%), then the nearest one within 5 m. When there was a long gap in the data, this matched different scooters, so I only allow the 5 m match when snapshots are close in time.
- The data was tricky. Times were in UTC, 12% of trips were "ghost" trips, and many "pickups" were really Bird servicing a scooter on the spot and leaving it there. That happened 109 times with abandoned scooters.
- Routes went through the sea when I used straight lines. I switched to OSRM to get real streets.
- Choosing only the highest scores sent the van across the whole city for one scooter. Choosing by "value per minute of detour" fixed it.
What I learned
- Real data is never clean: most of the work is understanding what each event really means.
- Talking to the people who will use the tool changes the solution. João's answers changed my priorities and my assumptions.
- Geospatial basics: metric projections, buffers, H3, routing engines, and why a straight line is not a route.
What's next
- A pilot with Cascais Próxima on a small server, storing events instead of full snapshots.
- Better plans for several runs with a vehicle routing solver (VROOM).
- It works with any GBFS operator, so it can scale to other cities.
- Cascais Próxima shared its bus data: I want to use scooter trips that start at bus stops to find where people need bus connections that do not exist yet.
Built With
- css3
- geopandas
- git
- github
- h3
- html5
- javascript
- leaflet.js
- logistic-regression
- numpy
- openstreetmap
- osrm
- pandas
- python
- scikit-learn
- shapely
Log in or sign up for Devpost to join the conversation.