98881A Odometry Devlog


Hey, I’m Cody from 98881A. This is a showcase of an odometry system (absolute position tracking) that I have been working on for the past month or so. Special thanks to @P_Mania for helping me build the chassis, my garbage build quality could never have gotten this to work.

Note that this is far from complete and optimal. Rotation correction isn’t much of a thing with the movement settings i have right now, this is just for getting to a spot asap. Videos of fun mecanum maneuvers (did someone say turning while moving linearly?) coming soon!

5225 PiLons Odometry Doc: https://www.vexforum.com/t/team-5225-introduction-to-position-tracking-document/49640/9



Looking great =)
I’ve been thinking of the exact same thing, turning when driving with holonomic would be op.
Looking forward to seeing that :grinning:

For driving to the point, what method have you used?
From the little turn at the end, I’m guessing you have been doing PID on straight distance/heading to point then exiting when robot is x away from point radius? Or are you doing some other special math.

1 Like


Yeah, it’s a PID loop that drives forward while trying to aim at the spot, then it exits 2 inches or so away



Pardon the garbage wiring. I haven’t had time to degarbulate it. :​P



Great work!
<20 characters>

1 Like


This is wonderful. I’m actually working on this myself. It should be a major game changer :smile:



How did you guys do your tracking wheel modules what wheels did you use? Great job!

1 Like


The most common design I have seen is the small tiny omni wheels on a piece of C-Channel and on the other side an encoder, with rubberbands pushing that assembly down onto the ground so it doesn’t skip.



yeah that’s exactly what we use, it’s pretty space efficient, though it can also be a challenge to line up the encoder and the other side that the axle goes through. We had a problem where the robot kept turning because one side wasn’t lined up and had a lot more friction compared to the other.

Also, I’m getting pretty close to finishing mecanum maneuvers. I’ll hopefully have a video of it this weekend sometime. Hey, maybe i’ll actually edit it too.



Now this is interesting, please keep us updated!

1 Like


We used the 2.75 in omni wheels (276-1902) and cut them in “half”. (To give them as much support as possible, the cut wasn’t directly down the center.)

Yes, it is possible without a bandsaw. Yes, I did this using a hacksaw. Yes, it was awful.



That’s amazing! Is there a tutorial or specific curriculum you have learned this from? I would love to learn how to code like that, but I can’t find a good way to learn it.



If you look at the thread about the PiLons mentioned in the original post, they have created an amazing resource showing the math behind the algorithm. To be honest though, it’s just a matter of breaking apart the different components of how a robot moves and some basic geometry and trigonometry. You could add Calculus concepts in there, but it’s not necessary to get a working algorithm.
My point is that you don’t need to “learn” this anywhere because if you break up the different parts of movement into small pieces, you will learn a ton from the process of creating the whole thing yourself.



Yeah, the pilons have a great write up. Also I would suggest learning how pointers work in c++ before trying to build an api, then writing a 2d vector class with support for adding, multiplying, and polar form. There are plenty of c++ tutorials online.

Ps: write an angle class too so that you can find the shortest path between angles (ie don’t go 359 degrees to the right instead of 1 degree left)



I don’t think single-function classes like the “angle” one you suggest is a very good idea, mainly because it’s mostly unnecessary to have a class for that purpose. One trick is to use normalized angle = atan2(sin(angle), cos(angle)). This has the effect of constraining the angle to [-pi. pi], which is very useful when you normalize pid error, target, etc. (Usually it suffices to normalize the very last angle-based value in all of your calculations)

Though, yeah, having a vector class has been very useful to me as well, both in writing odometry and my motion algorithm. The implementation comes out super clean.



Quick question related to odometry, could the v5 encoders on the left and right wheels be used to replace the quad encoders on the left and right sides? I’m working on a system of this for my team. Three encoders costs 6 out of 8 three wire ports. It may be nice to assume some losses in impact resistance for the ports for next year.



These wheels are typically prone to small amounts of slippage, the tracking wheels are tensioned against the ground so there is very minimal slippage.

1 Like


It’s not just impact that’s important, but also the fact that separate tracking wheels aren’t powered. When the robot starts moving, the powered wheels slip a bit, and they skid if you brake suddenly. Using most of the sensor ports is a disadvantage but being able to move reliably is probably well worth it. Plus vex might release a v5 to 3-wire port in the future



I made these two functions for rolling angle, there are many different ways of doing it

QAngle rollAngle360(QAngle angle) {
  return angle - 360.0_deg * std::floor(angle.convert(degree) / 360.0);

QAngle rollAngle180(QAngle angle) {
  return angle - 360.0_deg * std::floor((angle.convert(degree) + 180.0) / 360.0);


Actually, small, value-like classes that just wrap a single primitive field (or two), passed around as a value are perfectly OK. Any compiler worth its salt will optimize all the syntactic sugar away and will treat your class instances just like a primitive values with some extra behavior slapped to them. Your reward would be shorter, better readable code and the fact that you won’t forget to apply such extra behavior here and there…

1 Like