Language is C++
We have a Pigeon (V1) that is working as expected when calling .GetFusedHeading() ie returns degrees as a double that indicates the degrees turned since power on. The value is read in the drive subsystem periodic and displayed on smartdashboard and as you turn the robot the values change as expected. We also have a command that zeros the pigeon with a call to .SetFusedHeading (0.0); and this also works as expected. But it is doing strange things when setting the fused heading to anything other than 0.0. For instance if we call .SetFusedHeading(15.0) and then read it back again with a call to .GetFusedHeading() the value returned is only slightly more than zero (~0.23). We have checked the error code returned by SetFusedHeading and its always 0 which is supposed to indicate success.
Intellisense says both methods give/take doubles and expect/delivery the angle in degrees. We did find that if you call .GetFusedHeading immediately after calling .SetFusedHeading you will receive the value of the gyro before the call to .SetFusedHeading so there must be a slight processing delay. But repeating this command that sets it to 15.0 and then reads it back after printing the error code shows that it is setting to value around 0.23
Changing the set value from 15.0 to 180.0 had similar results (~2.8). After a bit of experimentation we found that you needed to set it to ~11500 to get it to set to180 degrees. It’s like the units are 1/64th of a degree for the .SetFusedHeading Method.
Has anyone else experienced this behaviour?
Do you have to multiple the degree set by 64 to make this work?
We are about to try a pigeon V2 and I read that the Fused Heading isn’t used anymore, what is the equivalent of .SetFusedHeading and .GetFusedHeading for the pigeon 2, and do these methods take and receive degrees or some other funky unit.
I just looked at the Intellisense again and noticed that the value .SetFusionHeading can take is +/- 23,040 degree. Just did the maths and this is exactly 360 x 64. Interesting, maybe the header need to be updated to say the units are 1/64th of a degree. CTRE API Documentation for Pigeon
Looks like you’re correct, setFusedHeading takes 1/64th of a degree from my testing. This is a bug that I’ve filed in our issue tracker, you can do your workaround of multiplying the desired set value by 64 in the meantime, but we’ll get this fixed up in our next release.
Pigeon2 always fuses accelerometer and gyroscope, so we simplified the api a little and only provide Yaw Pitch Roll methods. The equivalent for getFusedHeading is getYaw and the equivalent for setFusedHeading is setYaw. I just verified on my bench that setYaw accepts full degrees, not the 1/64th of a degree like you see with Pigeon1.
Hi Tytan,
I’m bit surprised that this have never been picked up before today. I suppose .setfusedheading to non zero values would only be used by teams that use field centric drive trains, and maybe they just worked this bug out and never reported it. Also, its only been in the last couple of years that you haven’t started against an alliance wall where the heading would be reset to zero at the start of an auto.
Is there a defined time period that is required before a .setfusedheading operation will take effect on the pigeon. ie how long do you have to wait before a .getfusedheading will return the value that has recently been set. If these calls are directly after each other I know that it will not have taken effect yet, but I don’t know what the actual time delay is. It would be nice if this was documented somewhere.
This could be a product of CAN status frames, maybe GetFusedHeading just reports the value reported in the last status frame and the .SetFusedHeading wouldn’t have been sent to the pigeon yet. This is just a theory as i’m not sure of how the .gets and .sets moves around the CAN bus.
This time delay has the potential to cause major issues for people following field centric auto paths where the robot is setup at a non zero angle to the field. If for example you call setfusedheading (30.0) and then immediately after this call reset you odometry to (x,y,30.0) at the start of your auto and the SetFusedHeading(30.0) hasn’t stuck yet, the odometry will initialize with whatever the heading was before you called .SetFusedHeading(30.0). (This happens because the odometry reset calls uses the current robot heading as one of its parameters.) Then when the .SetFusedHeading(30.0) takes effect and the next periodic odometry update updates the pose of the robot, the odometry class will think that someone has physically picked the robot up and rotated it, ie the field will suddenly spin by the amount the heading changed by from the .SetFusedHeading call. Then the field centric auto path will head off in a semi random direction (eg Assuming the robot was turned on after being setup on the field when facing 30 degrees the virtual field would be out by 30 degrees +/- what ever the gyro had drifted by since power on.)
I just re read this post and I’m guessing it won’t make sense to a lot of people. Sorry, I can’t find a better way to explain this potential problem. My advice would be to make sure that your set heading method has taken effect before resetting your odometry.
Regards
Warren
There’s two parts to this question, the first is to ensure the Pigeon received the set command and will properly set the fused heading, the second is when will the updated value be available.
For the first part, setFusedHeading has an optional second parameter, timeoutMs. If you specify a nonzero positive timeout the robot program will wait up to that time for a response from the pigeon that it received the request properly, an acknowledgement.
For the second part, you must wait up to the status frame period to get the updated value. For FusedHeading, the default period is 10ms. This is because getFusedHeading reads the cached value, so the cache must update with the new value, which happens every status frame period.
Regarding your odometry example, if I were the programmer I’d probably implement one of these two solutions (with preference to 2):
Continually set the heading in the disabled loop to the direction I expect to be.
Don’t use setFusedHeading at all and instead keep an offset in the robot code which updates once on autonomous init with offset = <desired heading> - getFusedHeading(), then replace every call to getFusedHeading() with getFusedHeading() + offset.
Another option could be to make the setting of the fused heading into a command that has an isfinished method that only returns true when the get heading is the same as the value that it is being set to. Then put this command in front of your trajectory following command in a sequential command group.
There was a thread reporting the same issue a week ago. I think this is a reminder that posting on an Internet forum offers the risk that the vendor may not see it. Better to use the vendor’s support infrastructure.
Sorry Joe,
I did search Chief Delphi and the internet before posting, but I didn’t find anything that matched my query. I must not have searched for the correct keywords.
I also believe Chief Delphi is an amazing resource of thousands of like mind people sharing their problems and solutions with every brand of FRC hardware and every type of software issue, so I think this is a great spot to post such a question. The number of times I have come to CD and found solutions to problems is countless. I can’t say I’ve ever gone to a vendors support site and just browsed their support articles for something to do. I also think that its very good that proactive companies like CTRE realise people use these forums and actively monitor them to see if people are having issues with their products. Cory from CTRE responded to my query very quickly, verified the problem was real, informed us that it was going to be fixed in the next release, offered work arounds for the problem. 5 Stars to CTRE.