JP Medina
Erse
Computer Engineering at USF, graduating May 2027. I build the layer where software meets the vehicle.
JP’s Garage
Ford Mustang
Mach-E
Path planning was my first task in the lab. Within a couple of weeks I owned the drive-by-wire integration instead, the layer underneath, where a plan stops being a plan and becomes an actual Mach-E moving across a parking lot.
The platform in the lab, sensor rack fitted
Nobody hands you that layer with documentation. I learned it from printed Dataspeed manuals and the CAN spec, because the vehicle integration was two people and there was nobody above me to ask.
The problem is that the two halves do not speak the same language. Autoware speaks physics: acceleration in meters per second squared, steering as a tire angle in radians. The drive-by-wire system speaks the car: steering wheel degrees, throttle percent, signed acceleration. Something has to sit between them and translate, fifty times a second, because the DBW subsystems fault out after about a tenth of a second of silence. There is no room to hesitate in there. You keep talking or the car drops out of autonomy. So the node caches, republishes, and runs a watchdog that commands a safe stop the moment the autonomy side goes quiet.
Then the lab moved a full drive-by-wire generation, DBW1 to DBW2 on firmware 3.0.0. New message set, different fault model, different rules for what counts as enabled. All of that landed on my node, because it is the only place in the system that knows the car's language. I rewrote its inside against the new spec and deliberately left its outside alone: same topics, same units, same contract the autonomy stack had been written against. Nothing above it had to be touched, and DBW1 stayed working alongside as a fallback. That is the entire reason a vehicle interface exists, and I got to prove it on hardware instead of arguing for it in a design review.
The last thing I changed was who decides how the car slows down. Its own controller was in velocity mode, so the stack would ask for a speed and the car would choose its own gentle way of getting there. That is fine until the plan depends on the deceleration. I moved it to acceleration mode, which put the profile back in the stack where it belongs and took the commanded braking limit from 1.5 to 8 meters per second squared.
TWO BUGS WORTH THE TRIP
Every subsystem reported healthy. The car still did not slow down.
The command went out on time, the DBW reported ready, and the logs showed exactly the deceleration I had asked for. Nothing in the system disagreed with me. The car just did not do it.
The problem was that two things were asking. In ULC mode the vehicle's own longitudinal controller owns the brake, and my interface was publishing a brake command alongside it. I assumed that was harmless because the enable flag was false. The Dataspeed driver does not read it that way. It forwards any brake message onto CAN whether or not the message is enabled, so the actuator was taking two streams from two owners and resolving them on its own. There is no arbitration layer above it to notice, and no fault code for two nodes talking at once.
The fix was small. The interface now stays off the brake entirely in ULC mode and commands it only when it genuinely owns it, for the comms-loss safe stop and for hybrid active braking. The rule is the part worth keeping: only send a brake command when you mean to take the brake away from whoever holds it. A command you did not mean is still a command.
Configured to spec, and still wrong.
A physical left turn came out as a right turn in RViz. The obvious suspect was a sign error in my own frame conversions, so I traced it hop by hop, every output of the interface and every frame convention, checked against REP-103. All of them were correct, which is a frustrating result until you realize what it rules out.
The sign was flipped in the Ouster driver's own documentation. The sensor had been configured exactly as written, so nothing in the chain looked wrong at any point. One config line fixed it and localization came back.
- Stack
- ROS 2 HumblerclpyAutowareDataspeed DBWCANPythonFoxgloveOuster lidarGenesys ADMA inertial and GNSSsensor driver integrationsensor calibrationREP-103
PROFILE
I am JP, a Computer Engineering student at USF graduating in May 2027. I work on the layer where software has to move a real vehicle.
Most of what I know came from the same loop repeated on three different cars: instrument the thing, find out what it actually does, then fix the gap between that and what it was supposed to do. On a Formula SAE car that meant tire models and a data logger. At Williams it meant telemetry systems that could not go down during a session. At RANCS it means a vehicle interface node standing between an autonomy stack and a drive-by-wire system that will fault out if you go quiet for a tenth of a second.
I like the debugging more than the building. The best day I have had in a lab was spending an afternoon proving that a bug was not in my code, hop by hop, until the only place left for it to be was the sensor configuration.
I speak Portuguese, English, German, and Spanish. I am comfortable being the person who reads the undocumented system and figures out how it works.

SKILLS
- ROBOTICS & AUTONOMY
- ROS 2 (rclpy) · Autoware · drive-by-wire integration (Dataspeed) · vehicle interface design · EKF state estimation · sensor integration and calibration · Foxglove
- SOFTWARE
- Python · C/C++ · MATLAB · Git · CI/CD · Linux · agentic AI development tooling
- VEHICLE & SYSTEMS
- CAN / DBC · vehicle dynamics modeling · control systems analysis · SIL simulation · verification and validation · on-vehicle testing · data acquisition (MoTeC, ATLAS)
- LANGUAGES
- Portuguese (native) · English (fluent) · German (fluent) · Spanish (advanced)
SELECTED WORK
CONTACT
Open to full-time roles starting mid-2027, and to summer 2027 internships.




