CTRE Encoder - Can't Zero / Reset Encoder Values

I have a mechanism where I am using the position feedback from the CTRE encoder and doing a calibration routine to set the initial position.

I’d like to zero out the sensors after that, and the documentation and code seems to suggest I can. We have roughly this:

… ->GetSensorCollection().GetQuadraturePosition();
… ->GetSensorCollection().GetPulseWidthPosition();

printf (stuff above)

… ->GetSensorCollection().SetQuadraturePosition(0, 10);
… ->GetSensorCollection().SetPulseWidthPosition(0, 10);

… ->GetSensorCollection().GetQuadraturePosition();
… ->GetSensorCollection().GetPulseWidthPosition();

printf (stuff above)

But the “sets” aren’t actually happening. The quad sometimes works, and the PWM seemingly never does.

I’m wondering if this is a timing issue somehow? I know the PWM takes some time to read, but we tested with sleeps and other code in between to no avail. Is there some other mechanism to zero out both sensors?

PS - my understanding is that in the API, “PWM” actually is the magnetic/absolute encoder, and “Quadrature” is actually the incremental/relative encoder. This seems to be correct with the values we see from reading both.

The Pulse-Width measurement on the magnetic encoder is a form of absolute measurement. Within a single rotation, you’re not going to be able to set the position - any point in the rotation is always going to give you the same value.

What the SetPulseWidthPosition call does do is reset the rotation over/underflow. As you do multiple rotations, the position register keeps track of these. Setting the position to 0 then clears this and gives you the absolute position within a single rotation.

Example: There are 4096 units within a rotation. You start at a position of 0 as measured by the pulse-width sensor and move one and a half rotations. Your pulse-width measurement is now 6144. You set the pulse width position to “0”, clearing the overflow. Your measurement would now be 2048, not 0, since your absolute position is still half a rotation away from the 0 point.

Since you’re using the timeout parameter in your sets, one of two things should be happening:

A) The set works (For quadrature, position goes to 0 and for pulse-width, position goes to the raw absolute value).
B) You get an error in the driver station saying that the set timed out (and thus probably didn’t work)

Does this match what you are seeing?

Ahh ok. For the absolute sensor that makes sense. I guess I was expecting it would go back to zero and start accumulating total turns from wherever in the circle it was at that point, until you power cycled it and it would then it would go back to wherever it absolutely thought it was compared to it’s absolute zero again.

In the usage where we (were trying) to set it to zero, I’m fairly certain it had never gone above 4096 or below zero. Our code doesn’t rely on the absolute position after we zero the quadrature out anyway (we use only quad after calibration), but it struck me as being weird and possibly tied to the quadrature not zeroing either.

  • Question - am I correct in assuming at power up the absolute encoder should always power up in a state between 0 and 4095 (never below 0, nor ever more than a full rotation accumulated?)

With the quadrature, I will follow up after we try again this afternoon, but by recollection prompting this post, the quads were definitely not zeroing. We are doing a bank of 4 different sensors at once, and occasionally one of them would zero. We added the code to grab the returned error value if there was one, and the SW person working that said it didn’t return an error, which is why I was thinking timing.

You can confirm that the zero operation on the quadrature sets a register in the encoder talon, and that should take effect “immediately”? I should be able to set it and immediately read it back and it should show zero?

Our mechanism is not visibly moving at this time, so I would expect it to go back to zero (+/- a few ticks of slop) after it gets set back to 0.

This is correct.

It’s not “immediately”, which is the reason for the timeout parameter this year. If you just fire the set command and immediately check the value, it’s probably going to be the old value since the new one hasn’t taken effect yet.

If you’re using the timeout, however, the function blocks until it receives a positive confirmation from the Talon that the value has been set - unless it waits for longer than the specified timeout, in which case it generates an error and stop blocking.
(See here: https://github.com/CrossTheRoadElec/Phoenix-Documentation#configuration-parameters---what-is-timeout-for)

So if you’re passing in a non-zero timeout and the function does not return an error code, you should be able to call the “get” function directly afterwards and receive the correct, new value.

Hello,

I am on the same team as Doug and am working on the same code.

We tried again and three of the talons resets to zero for our quadrature encoders but one was not working.

There are no errors reported when calling the setquadratureposition function.

Here is the code snippet and the logs.


std::cout << "Check Positions After Setting" << std::endl;

	currentPWMFL = RobotMap::swerveSubsystemFrontLeftRotationTalon->GetSensorCollection().GetPulseWidthPosition();
	currentQUADFL = RobotMap::swerveSubsystemFrontLeftRotationTalon->GetSensorCollection().GetQuadraturePosition();
	std::cout << "FL_CAL " << FL_CAL << "currentPWMFL " << currentPWMFL << "currentQUADFL " << currentQUADFL << std::endl;
	currentPWMFR = RobotMap::swerveSubsystemFrontRightRotationTalon->GetSensorCollection().GetPulseWidthPosition();
	currentQUADFR = RobotMap::swerveSubsystemFrontRightRotationTalon->GetSensorCollection().GetQuadraturePosition();
	std::cout << "FR_CAL " << FR_CAL << "currentPWMFR " << currentPWMFR << "currentQUADFR " << currentQUADFR << std::endl;
	currentPWMBL = RobotMap::swerveSubsystemBackLeftRotationTalon->GetSensorCollection().GetPulseWidthPosition();
	currentQUADBL = RobotMap::swerveSubsystemBackLeftRotationTalon->GetSensorCollection().GetQuadraturePosition();
	std::cout << "BL_CAL " << BL_CAL << "currentPWMBL " << currentPWMBL << "currentQUADBL " << currentQUADBL << std::endl;
	currentPWMBR = RobotMap::swerveSubsystemBackRightRotationTalon->GetSensorCollection().GetPulseWidthPosition();
	currentQUADBR = RobotMap::swerveSubsystemBackRightRotationTalon->GetSensorCollection().GetQuadraturePosition();
	std::cout << "BR_CAL " << BR_CAL << "currentPWMBR " << currentPWMBR << "currentQUADBR " << currentQUADBR << std::endl;

	std::cout << "Positions Checked" << std::endl;

	std::this_thread::sleep_for(std::chrono::seconds(2));

	std::cout << "Zero Encoders" << std::endl;

	ctre::phoenix::ErrorCode errFL = RobotMap::swerveSubsystemFrontLeftRotationTalon->GetSensorCollection().SetQuadraturePosition(0, 10);
	ctre::phoenix::ErrorCode errFR = RobotMap::swerveSubsystemFrontRightRotationTalon->GetSensorCollection().SetQuadraturePosition(0, 10);
	ctre::phoenix::ErrorCode errBL = RobotMap::swerveSubsystemBackLeftRotationTalon->GetSensorCollection().SetQuadraturePosition(0, 10);
	ctre::phoenix::ErrorCode errBR = RobotMap::swerveSubsystemBackRightRotationTalon->GetSensorCollection().SetQuadraturePosition(0, 10);

	std::cout << "flErr: " << errFL << std::endl;
	std::cout << "frErr: " << errFR << std::endl;
	std::cout << "blErr: " << errBL << std::endl;
	std::cout << "brErr: " << errBR << std::endl;

	std::this_thread::sleep_for(std::chrono::seconds(1));

	currentPWMFL = RobotMap::swerveSubsystemFrontLeftRotationTalon->GetSensorCollection().GetPulseWidthPosition();
	currentQUADFL = RobotMap::swerveSubsystemFrontLeftRotationTalon->GetSensorCollection().GetQuadraturePosition();
	std::cout << "FL_CAL " << FL_CAL << "currentPWMFL " << currentPWMFL << "currentQUADFL " << currentQUADFL << std::endl;
	currentPWMFR = RobotMap::swerveSubsystemFrontRightRotationTalon->GetSensorCollection().GetPulseWidthPosition();
	currentQUADFR = RobotMap::swerveSubsystemFrontRightRotationTalon->GetSensorCollection().GetQuadraturePosition();
	std::cout << "FR_CAL " << FR_CAL << "currentPWMFR " << currentPWMFR << "currentQUADFR " << currentQUADFR << std::endl;
	currentPWMBL = RobotMap::swerveSubsystemBackLeftRotationTalon->GetSensorCollection().GetPulseWidthPosition();
	currentQUADBL = RobotMap::swerveSubsystemBackLeftRotationTalon->GetSensorCollection().GetQuadraturePosition();
	std::cout << "BL_CAL " << BL_CAL << "currentPWMBL " << currentPWMBL << "currentQUADBL " << currentQUADBL << std::endl;
	currentPWMBR = RobotMap::swerveSubsystemBackRightRotationTalon->GetSensorCollection().GetPulseWidthPosition();
	currentQUADBR = RobotMap::swerveSubsystemBackRightRotationTalon->GetSensorCollection().GetQuadraturePosition();
	std::cout << "BR_CAL " << BR_CAL << "currentPWMBR " << currentPWMBR << "currentQUADBR " << currentQUADBR << std::endl;


Check Positions After Setting
FL_CAL 817 currentPWMFL 1107 currentQUADFL 146
FR_CAL 2685 currentPWMFR 2669 currentQUADFR 0
BL_CAL 911 currentPWMBL 902 currentQUADBL 0
BR_CAL 230 currentPWMBR 230 currentQUADBR 0
Positions Checked
Zero Encoders
flErr: 0
frErr: 0
blErr: 0
brErr: 0
FL_CAL 817 currentPWMFL 1258 currentQUADFL 150
FR_CAL 2685 currentPWMFR 2669 currentQUADFR 0
BL_CAL 911 currentPWMBL 902 currentQUADBL 0
BR_CAL 230 currentPWMBR 230 currentQUADBR 0
EndCAL

Any help would be good.

Thanks,
Drew

Drew -

Please e-mail our support (support@ctr-electronics) with the following information for the TalonSRX that isn’t setting position properly:

  • A brief summary of your issue - you can reference this thread if you want.
  • A screenshot of the web-interface self-test before you set the position.
  • A screenshot of the web-interface self-test after you set the position.

After running the last test where we said one, the next time we ran it we had a different selection of 3 with the issue. We can send the snapshots tomorrow…

I’m resuscitating my older thread here.

We’re still not entirely sure what the issue is after trying all sorts of different approaches. Ultimately it seems like the set command to the Talon (running a PID) just isn’t “finishing”. But only when we run the calibration routine. When we drive set points in teleop code that all seems fine.

We are calibrating and driving to the set point with a call from the Auto Init, and making a call to a function in a Subsystem.

They few people who have all looked at it seem to think it’s some sort of “timing”, “not finishing” type issue, or some odd interaction between WPILib and how command are called and completed, or possibly the Talon needs something else to “finish” it’s own internal loop.

In RobotMap we have tried swapping around the feedback device from the quad encoders to the absolute encoders and had similar results.

Anyone have any thoughts, similar situations, or links to anyone else calibrating a subsystem in C++ code?

https://github.com/team2053tigertronics/Robot2018/tree/master/Robot2018

Our team solved this problem by using the getSelectedSensorPosition() call to get the encoder’s location at start up. Then we do all our positional set() calls as relative to each encoder’s start position.