The trajectories are created on the computer for a few different reasons, actually:

- I wanted to use PathWeaver
- When I looked at the code for TrajectoryGenerator, it would have about doubled the amount of stuff I’d need to port. Then I realized there was no reason to do so, as I was going to generate trajectories of-robot anyway.

The trajectory follower is basically just exactly what WPILib provides, ported to Python. The only real change I had to make was to RamseteCommand, since I’m not using a command-based system (really just needed to put execute() into a loop).

Characterization was an interesting experience without the SysId tool or a very clear understanding of how it works. The direct measurements, wheel circumference and trackwidth, were easy enough; I actually already had them for the driving functions I had made previously (Follow a heading for a distance, or until colliding with something, or until reaching a line, drive an arc, turn in place, follow a line). After re-reading the Trajectory Tutorial section about characterization, ks and kv were easy to find, with the knowledge that they should be in Volts and Volts * Seconds / Meters, respectively. Although, instead of working with volts, I’m using motor percentages, so the range is -100 to 100. This doesn’t actually change anything significant; you just make everything that cares think it’s dealing with a 100V motor. Anyway, mimicking/reverse engineering the quasistatic test was easy (measure the speed at various different power levels), and gave me this graph:

X is applied power (%), and Y is measured m/s.

This graph also provides another useful value, max speed. It’s about 0.6 m/s.

Because the forward and reverse datasets line up so well, ks must be effectively zero— which makes sense, because the wheels are direct drive off the motors, and this test was done on a nice smooth floor. Separating the datasets confirms this, as ks should be the x-intercept of the regression line:

ks definitely isn’t negative.

Because of this, the entire dataset (minus the bits at the end where the robot was at max speed) can be used to calculate kv. It’s the inverse slope of the regression:

Now that we have wheel circumference, trackwidth, max speed, ks, and kv, what’s next?

The two constants left are the annoying ones, ka, kp, and max accel.

I tried to imitate the dynamic test by setting the power to 100, then rapidly measuring the actual speed. I got data, then has no idea what to do with it. This graph, with time on the x-axis and speed on the y-axis, gave me the value I ended up using for max accel:

I used the two points on either end of the steep bit of the graph, and found the slope of the line between them, giving a max accel of 20m/s/s. High, but believable, considering how light the robot is.

I eventually gave up on determining ka from measurements, remembering that a paper I found a while ago mentioned how to calculate ka theoretically. Great! I couldn’t find the paper again— until I realized it was a pdf, and thus downloaded. It’s

this paper. From said paper, ka = max voltage / max accel, so 100 / 20 = 5.

Fortunetly, I can use the SysId tool to calculate kp; in theoretical analysis mode, it needs ks, kv, ka, and max voltage, and it gives out a kp value. The response initially wasn’t great; here’s the wheel speed graphs again, with kp ~ 0.6 and no ramsete:

It’s close, but could be better. That’s when I realized that SysId has a maxVelocityError parameter, which was set to 1.5 m/s. Twice the max speed of the robot. Setting it to 0.1 gave a kp ~ 1500. I decided to try it anyway, with predictable results:

I started slowly increasing the velocity error parameter, which decreased kp (seemed like exponential decay), until I got these graphs with kp ~ 15:

It’s at least a little better.

EV3RT sounds like a really cool reason to learn C++ …unfortunately I have too much school too soon to start a large project like that.