Following a tracking wheel recording

So, I’m working on our autonomous for Worlds, and the driver suggested looking into the possibility of a record-replay system - something that we’ve (supposedly) seen used in another team’s 290-plus skills autonomous.

The obvious approach would be to snapshot the motor voltage (and other data, like pneumatics state) every few millis during driver control, then stitch those “frames” into a “tape” that can be saved to the SD card with some serialization voodoo and run back by a replay function at a future time. Unfortunately, I don’t have high hopes for this angle; it’s essentially another approach to 2D motion profiling, where voltage curves are generated mathematically and then followed more or less blindly, to varying results.

My alternate idea was to instead record the values output by our tracking wheel encoders, and then use some sort of black mathematics to “chase” the recorded encoder values autonomously. Unfortunately, I can’t really tell how plausible this is - a PID loop was my first idea, but I have no idea how you’d calculate the motor movements needed to accurately chase a set of ever-shifting target values.

If anyone could give me some pointers (or alternately, tell me this is borderline impossible for someone who’s in precalculus) then I’d be really grateful!

1 Like

You could try using the points generated by the tracking wheels as the waypoints for a pure pursuit controller.


Oh god. Are you in for a fun time.

I’ve been working on it (we call it a shadow auton) for around a month already. It is… difficult to say at the least. If youre doing this you’re probably a much better programmer than I was when I started it (it was 4 days before the tournament lol) so you might fare better.

Yes, this idea is possible. One of our sister teams managed to do it. The problem is they refuse to show anyone else (including me) their code. So I’m doing it myself. Currently my method is reading controller input and then saving integers. Then get those integers during auton and depending on the integer it executes a certain motor. The only issue with this is the refresh rate of the Brain. Because of the fact that the functions have to be different, there’s different times that it takes for the brain to run through all the code. Then it gets to the wait function. So if you say wait 10 ms, it won’t wait 10 ms, it’ll wait 10.1, 10.4, 10.2, and then in auton it’s even more variable. There seems to be only two solutions: A) set the refresh rate extremely low (think .2 seconds, maybe even .3) and then to manually make it refresh at 10ms. The problem is the vex Brain will only let you use 10ms intervals, which makes things harder, but also auton does something to the brain where the chrono module won’t work correctly. So you can’t use that. Im currently working on that, since once it goes 10 ms 10 ms 10 ms my auton is 100% accurate and we can just drive. But even though I have the code written and it “works” (use std::cout it’s a life saver with this thing) it still is inaccurate. Have to debug.

Good luck, because this will not be enjoyable.


To fix timing issues, you must time every drivercontrol loop iteration in microseconds (using Brain.Timer.systemHighResolution()), then you can create a custom microsecond wait command for auton that waits the amount of time measured in the drivercontrol loop


Yeah, you can do that, but the problem is it doesn’t work during auton for whatever reason. I’m looking for a fix but I don’t know if there is one

If you’re reading the data from a file on SD Card as the competition switch is plugged in, that would mess up your program. At least a for VexOS a year ago, I couldn’t output or input data from files when the competition switch was plugged in. I don’t know if it’s changed or not.


I’ve used a system of recording autonomous programming before and here my overall opinion on it.

It can be incredibly helpful if you aren’t prepared and have been working on your robot till the last minute. It can also be useful in matches where you can quickly create an autonomous program that compliments your alliance or directly counters your opponents. Now onto why I probably wouldn’t recommend it. It’s basically useless for autonomous skills as it becomes too inconsistent over the run, even in the 15 sec autonomous period it is quite inconsistent and turning is terrible, any changes on controller mapping and motor ports can cause changes and often cause things to stop working needing you to record again, and in my experience it just allows mechanical engineers to continuously tinker until the day before the competition instead of allowing programmers to work.

TLDR: It can be a good resource to have at a competition but it’s probably not a good idea to rely fully on it.


I in fact disagree with you. It’s extremely difficult to code correctly, but I whole heartedly believe it can work.

From my experience with it, the main problem is the refresh rate being unstable. In other words, the time it takes to do tasks are different each time you run it. Therefore you need to force the refresh rate to be a certain way. I’ve been trying a lot of experimentation with this, and it works for driver but not for auton. Couldn’t tell you why when I’m literally using the same function.

But I do think it is possible to get 100% accuracy. The reasoning I have for this is that because execution is the only issue, then the only thing the computer needs to do is execute the code like it does in driver, which it already has during driver.

The thing is, you definitely cannot only rely on it. Since I’m out of robotics and I’m absolutely exhausted of this (I spent maybe 100 hours on this in a month, and about 30 of those were in one week, it’s a lot), I’m taking a one month break until next season, but once next season starts I’m basically immediately beginning this again. If I can’t make it work, then I will shift all focus towards a normal auton. I wanted to make a normal one anyways just in case the reader auton breaks in a tournament. I’m going to recode all of it so I can A) incorporate it into my code (for now I’ve had a separate file and it’s unusable in a match), and B) optimize it and make it overall better.

I am aware it’s been over a month, but this was exactly what I needed, thank you!

Edit for anyone who may land here in the future: because pure pursuit doesn’t perfectly follow the path - it can “cut corners” and such on its way to the endpoint - it’s probably best to computationally generate your desired paths for pure pursuit rather than use a recording. Quintic splines are a good place to start; I’ll probably end up publishing my code down the road.


Pure pursuit is something that can work. There’s actually a couple of ways you can make a reader auton I think, and while pure pursuit is one of them, i think it’s not as fluid and dynamic. I guess that’s the trade off with this thing: accuracy for ability. When you’re done with your code, can you post a video of it in action?

Yeah, sure! It’s Nearly™ working, I just have to steal some better spline code and flog the curvature calculation into working properly lol.

At the moment it handles straight lines fine, but it oscillates around curves due to the calculated curvature not being aggressive enough. Who knows why, but I’ll get there eventually.

Edit: to clarify, it always gets to its destination regardless of path shape, it’s just… not the most direct about it lol.


@turbodog has a method of doing this that had one team with a 99% auto run in about an hour.

If you don’t want to use splines, you can use bezier curves, which are (I think) much easier on the computer for calculations.
There’s also a really simple formula for getting the curvature at a point
This video explains everything about bezier curves


The V5 Brain is actually SUPER fast at calculating quintic-spline-based trajectories. Like, faster than seems reasonable. It calculated a simple “benchmark” path (in quotes because each algorithm works a little differently, so using the exact same input wouldn’t work) in 71μs. Yes, microseconds. Which is actually more than twice as fast as an alternative dead-simple algorithm that just connects each waypoint with straight lines.

(I can’t really take credit for it, because all I did was steal the code from theol0403’s Pure Pursuit sim, then translate the hellish dynamically typed JS into nice C++ code.)


Ask and ye shall receive:

The first segment of our skills auton!

Some notes:

  • The consistency is simply sublime. The only caveat is that braking is currently a bit harsh and can cause jerk, which in turn means occasionally failing to grab goals. Fortunately this can be remedied - maybe by setting the motors to coast?
  • Pure Pursuit does not guarantee a precise exit angle from a path, but with some tweaking you can produce a decently consistent exit in the direction of your choice. Turn PID with an inertial sensor is a good way to close the gap if needed.
  • Pure Pursuit ALSO does not guarantee intersecting the waypoints specified in path generation, but like above this can be fixed by tweaking (for example, to ensure you hit a ringle cluster.)
  • The arm moves asynchronously using its own custom bang-bang controller and a potentiometer.

Edit: Here’s all the “front end” code needed to make the linked video happen:

  wayfarer.buildPath("Skills_1", {1.7, 18_in, 30, 1.0})
    .withPoint({1.0_ft, 1.3_ft})
    .withPoint({0.5_ft, 5.5_ft})
  wayfarer.buildPath("Skills_2", {1.5, 16_in, 30, 0.6})
    .withPoint({0.5_ft, 5.5_ft})
    .withPoint({-1_ft, 6_ft})
    .withPoint({-2.25_ft, 9.65_ft})