In this example, and in the documentation, we’re told that we should run
_talon.processMotionProfileBuffer();
about twice as fast as the duration of our trajectory points.
I’m just curious why this is implemented this way. If I’m running a trajectory point every 20ms, why do I need to tell the Talon to process its points every 10ms?
I’m not asking about the timing, but more why the talon needs to be notified instead of processing the buffer on its own. I’m sure I’m missing something, but I would have expected to be able to tell the Talon to start processing its buffer, and then check to see if it’s done.
We could have baked in a thread task into the CANTalon class, but I thought this would be a simple way to ensure there are no reentrancy or other thread-related issues without requiring much more testing/complexity.
I also did not want teams scapegoating a talon thread as the reason why their heavily threaded FRC program is not working or why their CPU utilization is high.
Additionally we did not want to assume what the correct frequency to call was, however the function itself is pretty fast (does not considerably block).
This could change in the future. I figured only advanced users would use motion-profile, and most users would use motion-magic since you don’t need to create a profile by hand (instead you set PIDF gains and cruisevel/accel to quickly get motion control).
Thanks for the quick reply. Would this even have to be baked into the class? Would it be possible to do this logic entirely on the talon? Maybe then the API would be something like:
_talon.setMotionProfileUpdateRate(int ms) //tells the talon how frequently to process its motion profile buffer.
_talon.startProcessingMotionProfile() //tells the talon to start processing its motion profile buffer.
Then we could use _talon.getMotionProfileStatus(_status); to determine if the MP has finished running.
One of the Talon’s greatest advantages is the parallel processing it brings to FRC. If I could give a talon a MP, tell it to follow it, and check back in to determine when its done, I’d be sooooo happy.
Why not just calculate the rate by dividing the delta time on the points in the profile by 2? Most users will get it right but why make them supply a value that could be determined automatically.
One of the Talon’s greatest advantages is the parallel processing it brings to FRC. If I could give a talon a MP, tell it to follow it, and check back in to determine when its done, I’d be sooooo happy.
That is how it works. But if your MP is large then it can’t be sent all at once. Instead it has to be streamed into the Talon as it executes, granted there is buffering in all the spots you would expect. The process function manages this periodically.
If I fill the top level buffer with at least 128 points (the size of the MPB on the SRX), how many of these will a single call to ProcessMotionProfileBuffer transfer, just 1, several, or fill the MPB on the SRX?
If I place multiple points in the top level buffer by calling PushMotionProfileTrajectory multiple times before a single call to ProcessMotionProfileBuffer, can I reduce the update period?
processMotionProfileBuffer will only process the next point based on timestep. That’s why it’s recommended to call processMotionProfileBuffer at a rate that’s twice as fast as the timestep between your motion profile points. It doesn’t transfer any points at all, but only processes the points that are already in the talon. You need to pushMotionProfileTrajectory before you can processMotionProfileBuffer.
You’ll want to place as many points in the top level buffer as possible before you start calling processMotionProfile buffer. If your motion profile has more points than can fit in the top buffer, you’ll need to add the remaining points as the top buffer empties into the bottom buffer. This can be done in the same method that also tells the talon to processMotionProfileBuffer.
Here’s how 319 follows our trajectories. It’s a command that loads a motion profile to each talon (left and right) and then tells them to processMotionProfileBuffer at a rate of 5ms (2x our trajectory timestep of 10ms).
/**
* This must be called periodically to funnel the trajectory points from the
* API's top level buffer to the controller's bottom level buffer. Recommendation
* is to call this twice as fast as the execution rate of the motion profile.
* So if MP is running with 20ms trajectory points, try calling this routine
* every 10ms. All motion profile functions are thread-safe through the use of
* a mutex, so there is no harm in having the caller utilize threading.
*/
void BaseMotorController::ProcessMotionProfileBuffer() {
c_MotController_ProcessMotionProfileBuffer(m_handle);
}
Thanks for the sample code - I’m going to take a look and see if I can better understand how this all works.
What transfers the points from the RoboRio to the MBP
If I have at least 128 points in the RoboRio buffer, how many iterations of #1 above are required to fill the MBP
Once the MBP is full, is there anything I need to do while it runs.
a. If my motion profile is fewer than 128 points - once the points are added to the MBP and the profile is started, can I then walk away and let the TalonSRX run the profile without doing anything else?
b. If my motion profile is greater than 128 points, as long as I add points before the MBP empties, can I add additional points at any time? So if each point has a duration of 10ms, and the full MBP duration is then 1280ms, can I add new points every 1000ms as long as each time I add points I fill the MBP?
You send points from the RoboRio to the Talon using pushMotionProfileTrajectory. This puts points in the top buffer on the Talon. When you call ProcessMotionProfileBuffer the Talon will move points to it’s bottom buffer from the top buffer.
You’ll send one point at a time to the buffer using pushMotionProfileTrajectory. If you have 128 points you’ll need to do it 128 times.
3a) Once all of your points are loaded you still need to call ProcessMotionProfileBuffer so the Talon can move the points internally.
3b) In theory yes this should work.
This is not true. pushMotionProfileTrajectory puts a point into the API’s top level buffer. The top level buffer is on the roboRIO. Each time you call processMotionProfileBuffer, if there is room (less than 128 points) in the low level buffer (on the talon itself) it will send the next point to the Talon’s buffer.
I do see that the documentation points to this being true. But why then does the TopBuffer had a cap on the number of points you can load into it? That’s what doesn’t make sense to me.
I believe the bottom buffer (on the Talon) is 128 points, while the top buffer (on the RoboRio) is 2048 points. With a delay of 10ms for each point, the top level buffer is sufficient for the whole autonomous period.
It’s clear why the bottom buffer is small - there is likely limited space on the Talon. I seem to recall, (but I cannot find), documentation stating that the 2048 limit is somewhat arbitrary, and could be changed with a little work (perhaps recompiling, but what I do not know). I’ll see if I can track down the documentation that spoke to this.
Do you recall the average duration of your points? 6.5.1 Sending the trajectory points in the Talon SRX Profile Reference Manual mentions 2048 but isn’t very explicit. I believe you can set durations down to as little as 1ms.
For example, this routine takes the double-array of trajectory points and passes it into the Talon object.
The routine clearMotionProfileHasUnderRun() is called first just in case we are interrupting a
previous MP. Then pushMotionProfileTrajectory() is called once per point. These functions
return immediately as the points are stored in the RIO initially. This buffer is referred to as the “Toplevel”
or API-level buffer.
If the profile is very large (2048 points or more) the function may return a nonzero error code. In
which case caller can periodically call pushMotionProfileTrajectory () to stream the profile into
the API, or use larger trajectory point durations, or modifying the library to increase the capacity.