VexU Legal Vision Tracking with Luxonis Oak-1 Camera

Hello everyone,

It’s been a while since I’ve been active on here… and since I’ve competed… But during the pandemic I became interested in computer vision and got the chance to back the Luxinos kickstarter for the Oak-1 camera. I quickly realized the potential usefulness for this device because of its small size and all computations are done on board so there is no need for large GPU’s like a Jetson. Unlike the current Vex Vision sensor, which is just a reskinned pixy, these cameras run at high resolutions and framerates. They also let you train your own custom models which give the flexibility for them to work in different environments. All these features are the basis of a more robust vision system that could be more comparable to something you would see in FRC.

Last summer I began playing around with getting these cameras to communicate with the V5 brain by using a Raspberry Pi to communicate through the micro USB port on the brain. Some of you might have seen those demo’s but here they are:

At the beginning of this year I decided to start a project to actually implement this onto something that would be more applicable to VRC and be a fun experiment for applying custom fabrication, physics, and programming into a presentable project. I decided to make a flywheel turret robot that would shoot the Turning Point plastic 3" balls into a goal around 5’ high from anywhere on the field, taking a lot of inspiration from the FRC game Infinite Recharge.

I designed and built this on and off during the semester and now that school is ended I got a chance to program and test it to a point that I am happy to share with everyone.

Unfortunately right now the code is not in a state where I want to release it publicly, and until that is done I won’t be working on any documentation on how the control system works for tracking the targets and how to communicate from the camera to the brain, but I WILL eventually be making all that public, I was just too excited to share this to wait until all of that is done.

I’m happy to answer any questions anyone has about it in the meantime, and I hope this possibly inspires some VexU teams to pursue using higher level vision targeting in future games :slight_smile:

Huge shout outs to:

  • Tomas Verardi from 375X for some of the Cad elements
  • Jess Zarchi for helping with parts of the design
  • Charlie Grier for helping with parts of the design
  • Andrew Strauss for helping me with Raspberry Pi to V5 Brain communication
  • Jared from 254’s presentation on vision tracking
73 Likes

In addition to the spectacular vision targeting can I just say this robot is incredibly well put together.

17 Likes

Nice! but where did you park your Lambo ?

3 Likes

Hello @Zach_929U,
Thanks again for sharing this on our Discord! And since you mentioned FRC, OAK-D has already been used there as well! See video here and the image below. Since we are trying to focus on robotic vision - are there any suggestions you could provide to improve our platform (depthai), or any painpoints you have experienced during the development of this awesome robot?
Thanks again, Erik (Luxonis)

7 Likes

Thanks for reaching out Erik,

The process was pretty smooth to get everything working. If you’re looking for suggestions to widen the user base though, an easier process for getting annoted datasets into trained models that can be deployed might be useful (I’m sure you are already working on this or it already exists and I just couldn’t find it).

From what I was able to find online the easiest ways for someone to go about this would be with the Roboflow Collab notebooks put out a couple years ago or use the built in roboflow train (you only get 3 credits though). I’m sure you can share some better resources you know of though.

Sadly the Collab notebook by Roboflow is quite outdated and parts of it also seem broken so I followed what was outlined here to write a python script that may help some people training locally on their computers that should take some of the headache of finding cudatool versions for pytorch and model conversions away.

Note, I threw this together in the last day so excuse how gross some parts of it are… and the lack of documentation. This was more just a proof of concept that I could get it to work but I thought I’d share anyways.

8 Likes

Feel free to ridicule this, I finally cleaned up the code a bit and organized it here:

I’d really like to make an explanation video behind the math of aiming and latency correction on the camera but I got covid at the end of summer and now my semester has started so I probably won’t get around to it until winter.

13 Likes

Hey Zach, this is super super cool work, thanks for sharing!

I have a few questions and comments. I skimmed the code a bit but didn’t deep dive, so apologies for any “read the code” moments.

Accounting for camera latency is a really nice move.

  • How consistent was the camera latency (so, “jitter”, if that’s a familiar term)?
  • How did you measure the camera latency or verify it was accurate?
  • Could you describe the turrets performance increase from applying latency compensation?
  • Did you consider accounting for other system latencies (computation, actuation, etc.)?
  • What computation (if any) was distributed on to the Pi vs the V5 Brain?
  • We’re you ever able to gauge the communication latency between the Pi and the V5 System to compare it to pure latency from the camera?

I see some feed forward information is being included in the turret aiming.

  • How is that integrated with the current drive command or trajectory?
  • Does the turret controller have reference velocities or accelerations included (maybe from the expected base trajectory)?
  • If yes to the previous, did you apply that reference trajectory to the flywheel speed control as well?

Overall, super cool stuff. I’ve done latency compensation for autonomous RC cars before, so I know it can be tricky. One technique we learned to measure overall latency was to command a sinusoid to the motors (could be speed or accel command) and then measure the speed or accel from your sensors. If you plot the reference command against the measurement, you get two sinusoids, where one is phase shifted by your overall latency.

Another cool thing I’ve been playing with lately is using a Real-time Linux kernel on my Jetson Nano (or RPi if that’s your vibe). I found latency and jitter decreased from 200us on average with max of 10ms all the way down to like 10us, max 60us. Just some fun anecdotes if you’re into that kinda thing.

Code looks nice. If you are shopping for suggestions, the first thing I do when I see new code is beeline to the header files, where I expect to see the comments and explanations for any public interfaces I might use. That way I don’t have to dig through source to get an idea of what’s up.

Again, 10/10 work. Robot is gorgeous. Thanks so much for sharing with everyone.

7 Likes

Thank you for the praise and suggestions for programming, I have done backend python for my previous jobs so I am not super familiar with more professional C/C++ formatting, but I’ll make sure to remember that for next time.

How consistent was the camera latency?

Using the python library for the Luxinos Cameras they provide built in functions to help you measure the Camera’s latency (Examples on how to use that here). In my early proof of concepts in the summer of 2021 I was using YOLO v3 to train the model and was getting ~50 ms of latency, but after switching to YOLO v5 I noticed that it went down to around 30ms (both at 1080p ~30fps). The 10 microseconds you are getting on your Jetson Nano are extremely impressive, and likely would not require any latency compensation for an application like this.

Could you describe the turrets performance increase from applying latency compensation?

Baked into the latency compensation is other ‘safety’ that uses the measured robots position with odometry, more importantly than latency compensation what this helped account for was lost frames caused by vibrations in the robot (I intentionally isolated the camera on thin polycarb to act as a dampener for flywheel vibration but overall robot shaking from movements still caused issues) or motion blur/game objects blocking the cameras vision of the target over small intervals of time.

I can tell you 100% that with the set up that I am using on this robot you will not be able to get anything remotely close without latency/frame loss compensation. I’ll go into a high level overview of how that works since you have other questions about it as well:

The first important thing to understand is how to calculate the distance from the target to the robot from the image. Because in this situation the height of the target is known and constant, you are able to use the pinhole model of a camera to simplify it down to simple right angle trigonometry using the resolution and FOV of the camera.

Latency compensation becomes important to use because as you can imaging the robot has moved between the time the image was taken and the time that the image was processed. So, the calculated position of the target using the method above does not reflect the state of the robot in the real world. (picture below)


Using this, what I do is take a new reference frame of the robots position every time a frame is captured by the camera, while that image is processing it will update the position of the robot in that reference frame, then when it is finally calculated you can use triangle math (law of sines/law of cosine) to create a third vector from the robots current position to the target which is what you should be aiming at right now.

Hopefully that makes some sense.

On top of this though, it is easy to imagine how you account for lost frames as well. If the object is not detected in the image when it is done being processed, you can use the calculated vector to the goal from a previous frame as a replacement to the actual camera reading. In essence, all this does is make the distance “Delta S” from the above image a longer value.

This creates a robust control system because the odometry is being used as a backbone to the camera, and the camera is used to reduce distance that odometry has to be accurate for in order to know exactly where the target is.

Did you consider accounting for other system latencies (computation, actuation, etc.)?

There is feed forwards built into the turret aiming that attempts to adjust for the velocity of the drive train but it is very basic. I would really like to make it able to shoot while driving around which would require a robust model for handling this, but other problems i’ll mention later are really what prevent this from being possible.

One thing that I did not account for was the acceleration of the turret itself being an issue, because the gyroscopic force of the flywheel and weight of the turret itself, the acceleration from being still was a headache to try to account for, there were points where I was using piecewise functions to scale error at lower RPM’s in attempts to make it accelerate faster but a tuned PID loop ended up working the most consistently across all robot speeds. If I were to rebuild this though I would definitely put 2 motors on the turret just to eliminate the issue all together.

What computation (if any) was distributed on to the Pi vs the V5 Brain?

The Pi handled exclusively the image processing, it would send the coordinates of the object to the V5 brain, then all the math/latency correction was done on the brain along with the other robot functions.

We’re you ever able to gauge the communication latency between the Pi and the V5 System to compare it to pure latency from the camera?

I never actually measured it, but it never was an issue so I assume that it is negligible (I am only sending a 6 character long string between the Pi and the Brain)

did you apply that reference trajectory to the flywheel speed control as well?

There is no flywheel speed control, the hood itself is on a curved rack and pinion system to adjust for the distance change. To answer the question though, it was baked into all the latency stuff mentioned above. Here is a video of the hood:
IMG_4837_AdobeExpress

Conclusion

The biggest problem I ran into with all of this, which I did assume would be an issue but decided to just ignore it, was that I was using the drive motor encoders for odometry instead of tracking wheels or any other form of position tracking. This lead to error in the calculations when the wheels slipped during fast accelerations or pushing against the wall. With tracking wheels I think this would work significantly better to the point where you could pursuit driving and shooting at any speed at the same time, which I would love to see someone do.

Hope this answered all your questions, if you have any more don’t hesitate asking. Good luck this season! :wink:

14 Likes

Awesome stuff! That pretty much answers my questions, but now I have a few more… :thinking:

In my early proof of concepts in the summer of 2021 I was using YOLO v3 to train the model and was getting ~50 ms of latency, but after switching to YOLO v5 I noticed that it went down to around 30ms (both at 1080p ~30fps).

I haven’t done any ML for image processing before, so I’m not familiar with YOLO beyond a quick google.

  • How difficult would you say it was to train your object detector and how robust was it?
  • Did you have to make your own dataset of a considerable size?
  • What were training times like?
  • Was it robust to different lighting conditions (i.e. would you ever recommend for use in real competition)?

The 10 microseconds you are getting on your Jetson Nano are extremely impressive, and likely would not require any latency compensation for an application like this.

As a side note, I should point out for anyone reading and interested that the numbers I provided for the Jetson represents measurements of the amount of time between when a thread should wake up, and when it actually wakes up. Using an RTOS or an RT Linux Kernel is typically a good move for robotics on a Jetson or a Pi, but will not magically fix the sensor latencies. The whole process Zach went through is extremely necessary when you want to really control something well. I’m also no RTOS expert, so if anyone needs to correct me, do it gently :laughing:.

One thing that I did not account for was the acceleration of the turret itself being an issue, because the gyroscopic force of the flywheel and weight of the turret itself, the acceleration from being still was a headache to try to account for, there were points where I was using piecewise functions to scale error at lower RPM’s in attempts to make it accelerate faster but a tuned PID loop ended up working the most consistently across all robot speeds. If I were to rebuild this though I would definitely put 2 motors on the turret just to eliminate the issue all together.

This is really interesting to me. I haven’t taken Dynamics in awhile, but Is the gyroscopic torque directly opposing the turrets rotation, or is the gyroscopic torque + the weight causing extra friction / binding in the turret mechanism?

Such clean engineering omg. :heart_eyes:

For you, anything. Just stay tuned… :ghost:

8 Likes

Haha sure thing!

How difficult would you say it was to train your object detector and how robust was it?

With the documentation that is out there it is out there for ML image processing it is not that hard. Because the OAK cameras use intel’s Myriad X architecture though you have to convert your models into the .blob format.

I know that on the Oak forums Luxinos mentioned that they were in the process of making a tool to help users go through this but I don’t think that it is out right now so you can either use the tool I posted in an earlier post in this thread, or one of the many Google Collab notebooks across the internet.

Did you have to make your own dataset of a considerable size?

As mentioned in the earlier post as well, I used Roboflow in order to create and annotate the dataset, which I recommend to anyone as a free tool that you can use for basically any project outside of this because of the number of formats they support for automatic exporting. For this project I used about ~200 pictures of the target from different distances, angles, and lighting conditions.

What were training times like?

Not long at all, I would say somewhere between 60-90 minutes on final version (high epoch) of the model that I wanted to but you can pump out a 90+ % confidence model within a 15-20 minutes for testing if you have a good enough Nvidia GPU. (I have a 1080Ti for reference)

Was it robust to different lighting conditions (i.e. would you ever recommend for use in real competition)

You’re able to get away with smaller datasets that are pretty easy to gather because YOLO applies its own set of distortions to the dataset you give it to create more training data and therefor create robust models. Without trying to hard to account for bad lightning, the models that I used were pretty robust and never failed because I was using it in a different room. The only times that it stopped working were in extreme cases of glare on the target and very dark rooms.

I am confident that this could work in practice at competitions as almost every event I’ve been too has had normal lightning. I think my biggest fear with taking it to a competition depends on what you would be tracking, depending how you are using it I could see objects on other fields being detected and messing up your system, something to think about when designing/choosing the angle of your camera.

This is really interesting to me. I haven’t taken Dynamics in awhile, but Is the gyroscopic torque directly opposing the turrets rotation, or is the gyroscopic torque + the weight causing extra friction / binding in the turret mechanism?

Correct, the gyroscopic force of the flywheel is opposing the rotational force from turret, intuitively you can think of the turret rotating like trying to push down on the edge of a spinning top. In a game like Spin up this would be way less of a problem since the wheels are sideways though.

It does not create binding because it is has decent tolerances and it’s all on ball bearings, but it does create resistance to motion for sure. pics below:



Can’t wait to see what you guys do :smiley:

11 Likes

Sorry to bump this thread again, Here are some renders of the CAD model that I thought I would share though!

As always, let me know if you have any questions!


:slight_smile:

21 Likes

Hello again everyone!

I got some time during spring break to go through and add tracking wheels with AMT-102V Encoders and some small custom omni wheels I designed (pic below), as well as rewriting a lot of the math for the latency compensation control system using these new tracker wheels.

The differences in performance are not super noticeable from the original video but for practicality of use in actual competition and overall accuracy it is leagues better. If you are planning to actually use something like this is the future definitely use something like this.

While I was at it, I decided to shoot and edit a little “reveal” to bring this whole project to an end, or at least a point where I am happy to end it and move on. Along with it I’ll also post a couple minute long video of me just driving around and shooting without any cuts.

Hope you guys enjoy, as always feel free to ask me any questions you have about it :slight_smile:

18 Likes

Would it be possible to send the CAD. I am part of a FIRST robotics team and I want to make this as an example to them of a turret with a hooded shooter on a small scale. This team is relatively small and it would be great if I could build one myself to show them. Not planning on selling it or using it for competition.

Thank you much appreciated

1 Like

I totally can, but the CAD model isn’t fully up to date right now so I’ll try to get it done in the next couple weeks and send it over with a google photos link of the build process. The other thing is that if you don’t already have the Vex v5 hardware it will get pretty expensive to build something like this (especially with all price hikes since I bought v5 back in 2018), so it might be worth taking parts of what’s been done here and using an alternative microprocessor you have available or one that is a bit cheaper.

Regardless though, if you need any help implementing anything let me know and I’ll try my best to help.

4 Likes

Ok thanks I got a bunch of v5 brains and motors for free from one of my friend’s who’s vex teams was quitting and had nowhere to go with the parts. I have access to a machine shop too so I can try to machine out the parts that look metal.

Look forward to building much appreciated for the CAD.

1 Like

@Nfoster Sorry for the delay on this, school has been killing me the last 2 weeks. This is gonna be a pretty long post too because I have a lot to explain to help you out! Lets start with the CAD model, it can be found here (CAD MODEL). Because this is exported as as a step, it unfortunately lost the transparent polycarbonate textures and are now set to the default gray color.

Anyways, lets go through how it was actually built. The most helpful thing I can provide is a google photos link that documents most of the build process, which can be found here (GOOGLE PHOTOS).

Now, lets go from the bottom up on how this thing was actually made:

  • The drive train is made of 8 wheels total, 2 of the old 3.25" omni wheels, 2 of the old 3.25" traction wheels, and 2 of the old 2.75" wheels drilled out to spin freely on 6-32 screws. The last 2 wheels are custom printed 40mm omni wheels that use the 3.25" vex omni wheel rollers.

  • The outer and inner drive rails cut from a 1/16th inch aluminum sheet on a CNC mill.

  • The Drive is cross supported using 0.5"x0.5" aluminum square tubing with 1/16th" wall thickness, which is plenty strong for this small scale stuff.

  • All the gussets that support the vertical tubes that hold the entire turret assembly up are milled from 1/16th polycarbonate, every other part on the robot that isn’t a standoff is 3D printed using PLA+.

  • The powered drive wheels are riding on 0.25" diameter ‘Deadshafts’ (which are just standoffs) with bearings on the wheel and gear for low friction.

  • The front roller is probably the most confusing assembly, i’ll try my best to explain it with images and videos:

    Because I wanted to use the FRC style latex tube over pipe trick for the intake, but also was using hard plastic balls to shoot, I decided that I needed to make some form of compliance on that front roller. To do this, I thought of a clever trick to hide a linkage inside the middle of the tube.


    There is a thin aluminum pipe inside of the wider roller that I thread and screwed into the polycarbonate structures on the outside, then a small 3D printed part with a pivot point and slot to ride on the inner pipe to connect to 2 bearings. Those bearings then connect to the pipe via another 3D printed hub not in the image to allow it to free spin, but also pivot up and down. If that made no sense, here’s a really old video when I was explaining it to other competitors so don’t mind how unprofessional it is haha.
    Turret Robot Front Roller - YouTube

  • The turret is built to minimize the dead space between the last intake roller and the flywheel, to do this I decided to stack the turret powering and bearing assembly radially instead of vertically, unlike what you normally see. To accomplish this I had the bearings ride on the outside of a belt around a big 3D printing timing pulley (More images in the google photos album):

  • To minimize the space the flywheel took up, I chose to directly attach the output of the motor to the internal v5 motor gear, which spins at 3600RPM. Because the only thing holding this tiny gear in is a thing Delrin bushing, a also internally put another skateboard bearing around that gear to support it:

That’s about everything that might be sneaky, I’ll say it is a huge pain to get the turret together though since you have to space the bearings that it rides on out, hold the belt tensioned, and screw down the top plate at basically the same time.

Some other misc. information that will be helpful:

  • All the screws and hardware on this is 6-32 button head machine screws EXCEPT for the intake screws, which are 8-32 Socket Head screws I believe.
  • Everywhere there is a ~0.375" or ~0.5" hole on a rotating part is where I put a press-fit nylon spacer into a 3D printed part to act as a bushing.
  • You will almost definitely have to mess around with tolerances to get these parts working on your printer. The motor mounts and hood angle changing mech are super finnicky.

Some things that I would suggest you actually change from my design:

  • First and probably something you 100% should change is the size of the bearings inside the flywheel motors. Find ones with a larger internal diameter and adjust the adaptor to the flywheel accordingly. I say this because the one I have on this robot has exploded 2 times after ~10 hours of use because it has very thin walls and is under a lot of stress while shooting. Even another 2mm of ID would do it wonders.
  • Design better Flex wheel holders for the intake, I did this super lazily and basically it is the bare minimum to work well enough for me to not care to upgrade them :stuck_out_tongue:

Other than that, I can’t think of much else to tell you about this. As mentioned before in this thread it uses a Raspberry pi 4, though you could use a 3b, or even a OrangePi to accomplish the same things I’ve done here.

Let me know if you need any more help, I will try my absolute best to respond quickly.

12 Likes

OH one more thing I forgot to mention in this, the bottom retaining part for the turret belt/bearings was originally made with polycarb but it was way too weak so I changed it out for a milled1/16th aluminum part.

5 Likes

@Zach_929U Thank you so much for your information and time. I appreciate it and will post pics when I am done though it may take a while.

2 Likes

Just One More Thing

Hello again everyone, I got some more time over the last couple days to do the last modification I want to make to this project, shooting WHILE moving.

The thing preventing this on older versions was the velocity imparted on the ball by the robot driving around causing the ball to arc differently through the air and miss the goal. To account for this, it now calculates the trajectory of the ball with those additional movements and aims the turret accordingly. Here’s a video of what its like now:

I believe that this is actually the end of the project since the current limitations of improving it involve using a camera with a bigger FOV and adding motors to the turret to reduce the acceleration time and allow for a heavier flywheel.

If anyone has questions about how I made this work going forwards, feel free to ask here or DM me on discord (username: _zach_m). I’ll also update all the code on a the Github within a few days once its cleaned up.

Happy new year!

11 Likes

Hey @Zach_929U it’s been a while and I have made a lot of progress on my version but I realized that whenever the turret base rotoates it come in contact with the indexing wheels. Is there a fix around this?

1 Like