Skip to content
This repository has been archived by the owner on Sep 28, 2021. It is now read-only.

What happens if you call getBulkInputData() multiple times? #9

Closed
EddieDL opened this issue Oct 27, 2019 · 10 comments
Closed

What happens if you call getBulkInputData() multiple times? #9

EddieDL opened this issue Oct 27, 2019 · 10 comments

Comments

@EddieDL
Copy link

EddieDL commented Oct 27, 2019

We have created several sub-system classes that utilize sensor data from the expansion hub. We have switched to getting this data using getBulkinputData(). Does the logic of getBulkInputData() have any logic to ensure multiple hardware calls are being made in a given "update cycle" or do we need to figure that out in our implementation?

@Windwoes
Copy link
Member

Any time that getBulkInputData() is invoked, an actual USB call to the Lynx hardware is made, unless the OpMode thread has its interrupted status flag set.

@EddieDL
Copy link
Author

EddieDL commented Oct 27, 2019

Is there a good way to call getBulkInputData() once a hardware cycle in a LinearOpMode?

In a basic OpMode think I would just make sure at the top of the loop getBulkInputData() is called and it is never called anywhere else. Then any other place where I have gotten the ExpansionHubEx object from the HardwareMap it will have the most recent data.

Another option I am considering would be to wrap ExpansionHubEx and implement a "throttle" to how often getBulkInputData() can be called. if(now - lastUpdate > X) { getBulkInputData()}

Just wondering if you have any suggestions or thoughts.

Perhaps these calls are so much faster it doesn't matter if you make them a few extra times.

@Windwoes
Copy link
Member

@EddieDL There is no such concept of a "hardware cycle" when using an Expansion Hub. Unlike Modern Robotics which has background threads for each module and periodically reads/writes, every single API call, e.g., DcMotor#setPower() will immediately cause a bus transaction when using an Expansion Hub.

If your linear opmode is structured in the form of a state machine, I would update the bulk data once per iteration of the master state machine. If you're not using a state machine, then the only option I can think of other than the time-throttled method you mentioned, would be to have a background thread that continually polls bulk data and provides your main thread access to it through a volatile variable. However, be aware that because only one thread can have a bus transaction to the Expansion Hub in flight at any given time (this is because RS-485 does not have any collision prevention), using that method may cause the bulk data poller thread to "starve" your main thread, or vice-versa.

@EddieDL
Copy link
Author

EddieDL commented Oct 27, 2019

Seems like I was stuck still thinking there was a background hardware thread, even when using the Expansion Hub. I guess this makes it even more beneficial to move to the bulk read approach.

I am pretty sure we are going to need to implement the time-throttling I mentioned. Do you have any suggestion for a sane throttle? Based on reading and your comment ftctechnh/ftc_app#542 (comment), I was thinking about making it 6-10 ms. I thought about making it the update interval on the Rev Module, but I wasn't exactly sure what that is.

@Windwoes
Copy link
Member

@EddieDL Keep in mind that each motor set power command takes 3ms (x4 motors = 12ms). Also doing an IMU read will cost you about 7ms. So I would recommend somewhere in the range of a 20ms throttle.

I'm not entirely sure what you mean by "the update interval on the Rev Module". The "update rate" to user code is entirely defined by how many bus transactions you're doing. If you're only doing a single bulk read (and nothing else), you can push in excess of 300Hz. But as soon as you start adding more commands that plummets sharply. If you're referring to the internal update rate inside the Hub's SOC, I think for DIO that's 100Hz, not sure about encoders. But in any case, with 4 motors and bulk read, you will never be able to go faster than 66Hz....

@EddieDL
Copy link
Author

EddieDL commented Oct 28, 2019

That is very helpful. I was asking about the internal rate of refresh for various components inside the Hub. My thinking was to potentially use that as an input to calculating a good throttle.

Now I understand what you are saying a little bit more and I also see why there could be HUGE gains by expanding the SDK and Hub to support bulk writes, data exchange, bulk i2c reads, etc.

In my case, we are going to have the following configuration:

  • 4 motors
  • 6 encoders (this means I need to do 2 bulk reads)
  • IMU

If I understand the math correctly, that is 4 * 3 ms + 2 * 3 ms + 7 ms = 25 ms. Does that seem right?

Thanks again for all the help.

@Windwoes
Copy link
Member

Yes that seems right, in theory anyway. What I would suggest is to make a Linear OpMode with a loop that reads those things, and average the loop time over maybe 250-1000 iterations. Then make your throttle ever so slightly faster. Also, make sure to use SDK v5.3 and firmware 1.8.2 as they contain optimizations for I2C reads.

@David10238
Copy link

What gluten free did was they polled the bulk data in their robot class then set all the motors
https://bitbucket.org/PeterTheEarthling/version-4.3/src/master/ftc_app-master/TeamCode/src/main/java/Hardware/RevMotor.java
https://bitbucket.org/PeterTheEarthling/version-4.3/src/master/ftc_app-master/TeamCode/src/main/java/HelperClasses/Robot.java
What we do is we have for every instance of the LynxModule a boolean that stores weather or not we've read that hub yet. At the beginning of each iteration, we set all the booleans to false, then the first time we attempt a read we turn it to true. I have to clean a couple of things up mainly around exception handling, but this is what the core of our system looks like. We just call BulkDataMaster.clearAllCaches() then we just call all our stuff with simple calls like. gyro.heading_deg or motor.ticks https://github.com/David10238/SkystoneApp/blob/master/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/bulkLib/BulkDataMaster.kt
https://github.com/David10238/SkystoneApp/blob/master/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/bulkLib/BulkPacket.kt

@Windwoes
Copy link
Member

@David10238 oh, reading once per iteration is absolutely the best way to do it. But unless your code is written as a state machine, that's not possible.

@EddieDL
Copy link
Author

EddieDL commented Nov 13, 2019

Thank you for all of the help on this. I have implemented something that will work for us, based on all of your input.

@EddieDL EddieDL closed this as completed Nov 13, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants