Using encoder with talon SRX

Hi
Does anyone have any sample Java code on how to use encoders with the SRX?
Having trouble finding any on the web and not sure which classes to use.
Thank you

Check out the Talon Software Reference Manual.
http://www.ctr-electronics.com/talon-srx.html#product_tabs_technical_resources

Some key sections…
Section 7.3 for selecting the sensor.
Section 5.3 for getter functions.
Section 12 for closed-looping using the internal PIDF loop inside Talon firmware.
Section 13 for setting/changing the sensor position.

Thank you very much for your quick reply. I did not see the coding manual. What I was hoping for was more context I’ve been through a lot of those manuals. We had problems using the CANTalon class last year, and we were not sure if it was really necessary to use some other class to get it to work. Is there anyone out there with actual code they can share using quadrature encoders?

So you’re saying you still can’t find the software ref manual? Or you didn’t notice it before but now you have it? I guess I’m not sure what you’re asking for.

Do you remember what was the problems from last season with CANTalon?

You should also read up on the web-based config, which will allow you to see quadrature position and velocity, even if there is no deployed roboRIO code.

I did not know there was a CTR coding manual. I’ve been reading it now for an hour or so. Thank you. I don’t have specifics yet on the problems other than canTalon did not work with our CAN BUS. The challenge is trying to figure out how it works without examples. We have a qudratue encoder on our motor, and we are accessing it through the CAN, but it is not clear what classes to use. Are there any examples out there of just basic usage?

I think I understand the original posters point - I’ve struggled with this a bit as a mentor myself. I had found the coding manual last year but never got things working quite right for us. I’m a java developer by trade but robotics is only a hobby and I fear some of the background context that most presume is known in advance is a bit of a hole for me.

Things I didn’t see:

  • There are encoder classes if I remember right in wpilib. However if we hook the encoder to the talon we don’t use them at all right?
  • a lot of the built in PID type functionality can’t be used if the encoders are hooked to the talon right? The PID classes all expect to get the encoder feedback directly.
  • I assume hooking the encoders to the talon directly reduces overhead on the roborio and certainly free’s up ports. I’d love to see a post that covers the pro’s con’s of either scenario and how you might use the wpilib PID controllers when the encoders are hooked directly to the talon srx

I’m going back to reading the talon programming manual again (its been most of a year) and this year we have the luxury of a bench bot we can more easily experiment with so hopefully I’ll be in a better position. Last year encoders weren’t critical but this year I’m really hoping we can do better in autonomous mode than last year. Other topics that would be interesting for me would be a ramp/brake tutorial for dummies. I have yet to search on that one so maybe it exists. The comment has been made that we accelerate too quickly and stop too quickly so I’m assuming that we need to learn about those.

2 Likes

If you hook the encoders to the talon directly, you don’t need to use any of the WPI PID classes at all. All the encoder feedback and output is handled through the talon. For example, this code changes the talon to position mode, sets the feedback device, and sets the PID constants.

talon.changeControlMode(ControlMode.Position); //Change control mode of talon, default is PercentVbus (-1.0 to 1.0)
talon.setFeedbackDevice(FeedbackDevice.QuadEncoder); //Set the feedback device that is hooked up to the talon
talon.setPID(0.5, 0.001, 0.0); //Set the PID constants (p, i, d)
talon.enableControl(); //Enable PID control on the talon

Then later in your code, you can use the talon.set() method to set the talon’s position (or velocity, or percent, etc.)

talon.set(5000); //Tells the talon to go to 5000 encoder counts, using the preset PID parameters.

As for the ramp/brake stuff, you can set that easily also.

talon.setVoltageRampRate(rampRate); //Sets the max voltage ramp on the talon
//This affects both starting and stopping

You can also switch control modes and PID parameters later (to allow manual control). Do the exact same as earlier.

talon.changeControlMode(ControlMode.PercentVbus); //Change control mode of talon, default is PercentVbus (-1.0 to 1.0)
talon.setPID(0.0, 0.0, 0.0); //Set the PID constants (p, i, d)
talon.enableControl(); //Enable PID control on the talon
1 Like

Thanks - that appears to be helpful. On the position front we weren’t using the quad encoder (we have them though) we were using a pot that we hooked directly to the roborio - It was painful trying to arrive at the correct parameters to prevent oscillation or error on the steady state. This year I bought an absolute position encoder - we only used position on the motor that was raising/lowering a lifting arm. I suspect your example will work well with the absolute encoder.

I’m taking this week to go back through the programming doc’s - last year we had mechanum wheels and I hadn’t figured out how to make use of the encoders properly with the robot drive in mechanum mode. I doubt we’re going to use mechanum this year but I may still try to solve that so that we have it in our toolbox so to speak.

My goal this week is to integrate a few things like an example autonomous mode that will take a tank or arcade drive, drive it forward 10 feet, pivot 90’ right, Go forward 10 feet, and so forth - try to create an acurrate box pattern. I’ll post back any specific questions I hit - usually when I am doing this sort of thing I’m bogged down at work and trying to figure it out with the team working 6 days a week. Doesn’t give me much time to methodically work through things. This year I have my own RoboRio at home that I can work through things in peace and quiet so that I have a better understanding when working with the students. Once I get that working I’ll have to figure out if we need to integrate a gyro into the equation.

Ok - so I got my hardware setup. I have 2 talon srx’s setup with 2 of the optical encoders from andymark. I created a test button and added the following to the execute on the command for the button. It starts and stops the motor but I’m not sure it is really doing what I want. Basically I’m working towards a command that will cause the robot to travel forward x inches to be used in autonomous mode. The code below is what I used…the position on the encoder doesn’t seem to wind up anywhere close to where I expect it to be also I think I’d have better results if it was running slower or there was a load on the wheel. The output from the print statements is before the code for ease of following. Obviously I’m totally overlooking something so any guidance is appreciated.

Start of Execute
-264
-264


    	System.out.println("Start of Execute");
    	RobotDrive drive = RobotMap.driveSystemdrive;
    	CANTalon talon =  RobotMap.driveSystemCANTalon1;
    	talon.changeControlMode(ControlMode.Position); //Change control mode of talon, default is PercentVbus (-1.0 to 1.0)
    	talon.setFeedbackDevice(FeedbackDevice.QuadEncoder); //Set the feedback device that is hooked up to the talon
    	talon.setPID(0.5, 0.001, 0.0); //Set the PID constants (p, i, d)
    	talon.enableControl(); //Enable PID control on the talon
    	int currentPosition = talon.getEncPosition();
    	System.out.println(currentPosition);
    	talon.set(5000); //Tells the talon to go to 5000 encoder counts, using the preset PID parameters.
    	System.out.println(talon.getEncPosition());
    	finished = true;

For a benchtop system it does need a load or brake on the wheel to provide some inertia, otherwise the mechanical system will overshoot. It has no reason to slow down or stop and will continue to coast until your system drives it back the other way.
A normal FRC robot will have 150 lbs/# of wheels on top of carpet to resist movement.

Thanks - I’m rigging up a breaking system with a bungie cord to put a load on it. I guess what confused me (correct me if I’m wrong) is that I have a get encoder position before and after the call to set position and it has the same value before and after - I’d expect a difference. However I’m guessing thats because its an async call instead of a synchronous call to set position - another words it returns immediately instead of after the move is complete.

Also I’ve noticed that the command is getting called a minimum of 3 times for one button push - is this due to button bounce? I assumed the framework would have handled that. I think compensating for that may help

You are correct. The calls are non-blocking, so they occur as fast as the processor can execute instructions. The Set call simply sets a requested value. It doesn’t stop to examine changing inputs.
The subsequent calls are actually measuring how far the wheel travels in the time taken by the processor to execute some number of instructions.

The multiple actions per button press isn’t mechanical/electrical bounce, but the limit of human reflexes. Your code needs to do a check:

  • Only when button changes state from false to true = perform action
  • Not when button = True, or = False, or is changing from True to False

You’ll probably need to reconsider your P value once you get it working. Think about what speed the Talon will be outputting when the encoder reads 2 ticks from the setpoint.

Hey riftware,
The code looks right, assuming the sensor and motor both move in the positive direction.

For tweaking gains (and general diagnostics) you’re best bet is to look at the Self-Test results (and the gain values that are under the self-test results). That displays your motor-output, the ClosedLoopErr, and sensor pos/vel.

This will tell you how much error the closed-loop sees between the target and sensor. Most likely your gains just need tweaking.

ClosedLoopErr is what is multiplied by Kp, and is equal to your target - current sensor position (or velocity if that’s selected). Since you are using quad encoder, then there is 4XCPR units per rotation where CPR=countsPerRotation. Talon is always in 4X mode.

Integral accum sums closedLoopErr every 1ms.
dErr is the change in ClosedLoopErr per 1ms.

See section 2.4 in Talon SRX Software Reference Manual for how to get the self-test results.

Ok - I just re-ran through the document and didn’t see it. Is there a recommended solution so the command only fires once per button push? I’m assuming I create a static flag and toggle it true at the beginning of execute and false when I’m done? I also assume my encoder position logic needs to enter a sleep/poll loop to determine when the command is really done? After which I can toggle the static busy flag to prevent the command from executing multiple times. Also this is borderline about encoders at this point if I need to grab a different thread let me know.

If you are using RobotBuilder then you can to a “whenPressed” action…
https://wpilib.screenstepslive.com/s/4485/m/26402/l/255441-connecting-the-operator-interface-to-a-command

If you are using command classes yourself there is a Button class you could wire into the scheduler.

If you are just writing straight java, I usually just copy/paste the following…


//instance variables
    boolean ] btns  = new boolean ] {false,false,false,false,false};
    boolean ] last  = new boolean ] {false,false,false,false,false};


//get latest
    public void teleopPeriodic() {

        btns[1] = _joy.getRawButton(1);
    	btns[2] = _joy.getRawButton(2);
    	btns[3] = _joy.getRawButton(3);
    	btns[4] = _joy.getRawButton(4);


    	if(!last[3] && btns[3]){
    		//btn3 just pressed, do something
    	}


// bottom of teleop save all btns into last
		for(i=0;i<last.length;++i)
			last* = btns*;

**

As for the self-test and PID things - I had already verified the encoder position is increasing when the talon flashes green so we’re good there. The pid values were just ones that were in example earlier in the thread. Honestly I have a bit of a mental block on PID. I must have read the tutorials a dozen times. I’ll take a look at it in just a moment. Thankfully I’ve got my first decent stretch of time with a test rig of my own so I can use my usual tactic of sheer stubbornness to get this down pat. Thanks for all the help everyone.

I think I had found my problem - I am using the 2016 version of Robotbuilder I built from source (yay talon srx now works!) - I hadn’t noticed when I threw the button in that it defaulted to while pressed not when pressed.

Ok so let me expose the massive understanding issue I have.
I want to travel 10’ on one wheel.
1: Asuming a 6" wheel diameter I get a circumfrence of 18.84 inches I believe this means I will need to travel 6.36 revolutions.
2: I am using the e4p-360 encoder so its 360 ticks per revolution, except that its quadrature so I multiply that by 4 meaning we really see 1440 counts per revolution. Based on that I think I want a target of +9158.4 (or negative if I’m going backwards.

3: (a little hazier here) - Do I need to include current position or is that implied? My concern is I don’t want to do whatever it takes to get to count 5000, I want to add or subtract 5000 to where I am now - or do I need to reset the counter to 0 first?


int currentPosition = talon.getEncPosition();
talon.set((currentPosition + 9158));

4: PID - P is the constant that gets multiplied by the error (initially the error is 9158 when we start?). Is there a good rule of thumb for picking a P on a drive system as opposed to something like an Arm?
‘I’ is the Integral - a smaller value gives faster control? - Is there a range to work within or a rough rule of thumb?
‘D’ is the derivative which if I understood correctly helps prevent overshoot? Higher value reacts faster?

I’ve tried the numbers from both previous examples and I’m going to continue to try them, but what I don’t understand is how they were chosen.

Also in all of this is there a way to indicate an acceptable error margin? Like +/- 5 inches or something?

Finally - when I call this command is there a way for me to set how fast I want to travel (like 1/2 speed or something?)

I may have just got it to work (perhaps)!

I think my problem was I was calling talon.set(9158) instead of setPosition(9158)
I say perhaps because the selftest screen shows much different numbers than talon.getEncPosition() …still working on it but I may be making progress.