Analog Encoder - Java Help. Am I doing something wrong?

So I am losing my hair over here trying to figure out using this Analog encoder we have plugged directly into our Talon SRX. On the tuner I can see the position changing as we run the motor. The issue now I guess is in our code. We used the example from CTRE to have the motor go to a certain position when a button is pressed but the motor just goes to max power and continues to spin forever, the initial position is lower then our target so that isn’t the issue. Can anyone see anything wrong with this code?

Here is a link to our Github if you would like to see it all.

package frc.robot.subsystems;

import edu.wpi.first.wpilibj2.command.SubsystemBase;

import frc.robot.Constants;

import com.ctre.phoenix.motorcontrol.ControlMode;

import com.ctre.phoenix.motorcontrol.FeedbackDevice;

import com.ctre.phoenix.motorcontrol.NeutralMode;

import com.ctre.phoenix.motorcontrol.can.TalonSRX;

import edu.wpi.first.wpilibj.Encoder;

public class turnSubsystem extends SubsystemBase {

  /**

   * Creates a new Turner. https://github.com/CrossTheRoadElec/Phoenix-Examples-Languages/blob/master/Java%20General/PositionClosedLoop/src/main/java/frc/robot/Robot.java

   */

  

   TalonSRX turnTalon;

   

   public Encoder turnEncoder;

   public final double HOLD_POWER = 0;

   public final double Turn_POWER = 0.4;

   public final double Stop_POWER = 0;

   public final double Incremental_value = 1;

   StringBuilder _sb = new StringBuilder();

   double targetPositionRotations;

  

  public turnSubsystem() {

    turnTalon = new TalonSRX(Constants.talonTurn1);

    turnTalon.setNeutralMode(NeutralMode.Coast);

  

        /* Factory Default all hardware to prevent unexpected behaviour */

        turnTalon.configFactoryDefault();

        

        /* Config the sensor used for Primary PID and sensor direction */

        turnTalon.configSelectedFeedbackSensor(FeedbackDevice.Analog,

                                            Constants.kPIDLoopIdx,

                                            Constants.kTimeoutMs);

        /* Ensure sensor is positive when output is positive */

        turnTalon.setSensorPhase(Constants.kSensorPhase);

        /**

         * Set based on what direction you want forward/positive to be.

         * This does not affect sensor phase. 

         */ 

        turnTalon.setInverted(Constants.kMotorInvert);

        /* Config the peak and nominal outputs, 12V means full */

        turnTalon.configNominalOutputForward(0, Constants.kTimeoutMs);

        turnTalon.configNominalOutputReverse(0, Constants.kTimeoutMs);

        turnTalon.configPeakOutputForward(1, Constants.kTimeoutMs);

        turnTalon.configPeakOutputReverse(-1, Constants.kTimeoutMs);

        /**

         * Config the allowable closed-loop error, Closed-Loop output will be

         * neutral within this range. See Table in Section 17.2.1 for native

         * units per rotation.

         */

        turnTalon.configAllowableClosedloopError(0, Constants.kPIDLoopIdx, Constants.kTimeoutMs);

        /* Config Position Closed Loop gains in slot0, tsypically kF stays zero. */

        turnTalon.config_kF(Constants.kPIDLoopIdx, Constants.kGains.kF, Constants.kTimeoutMs);

        turnTalon.config_kP(Constants.kPIDLoopIdx, Constants.kGains.kP, Constants.kTimeoutMs);

        turnTalon.config_kI(Constants.kPIDLoopIdx, Constants.kGains.kI, Constants.kTimeoutMs);

        turnTalon.config_kD(Constants.kPIDLoopIdx, Constants.kGains.kD, Constants.kTimeoutMs);

  } 

  @Override

  public void periodic() {

    // This method will be called once per scheduler run

  }

  public void Turn() {

    turnTalon.set(ControlMode.Position, Turn_POWER);

   }

    

  public void StopTurn() {

    turnTalon.set(ControlMode.PercentOutput, 0);

  }

  public void resetEncoders() {

    turnEncoder.reset();

  }

 

  public void HoldHeight() {

    turnTalon.set(ControlMode.Position, HOLD_POWER);

  }

}

I would output your encoder position in your periodic() method to make sure it is moving in the correct direction. You’re also just telling it to go to position 0.4 which doesn’t feel correct. I’m also not a big fan of you re-using Constants.kPIDLoopIdx everywhere you want a 0 regardless of the context. Makes it hard to understand what you’re doing.

1 Like

As was mentioned, you have some places where you have Constants.kPIDLoopIdx where I think you meant Constants.kSlotIdx.

Have you confirmed that the motor phase is correct, so that a positive output/command moves the mechanism position up/forward/out? Have you confirmed that the sensor phase is correct, after setting the motor phase, so that a positive motor command causes the sensor value to increase?

Right now, you are commanding the motor to position 0.4, which I don’t think does what you intended it to do, as well as the variable being named Turn_POWER. If you compare to the example code you linked, the position target there is set to leftYstick * 10.0 * 4096 corresponding to 10 Rotations * 4096 u/rev in either direction for the mag encoder they used. In this case, you would use 1024 u/rev for the range of your encoder instead of 4096 because it is an analog sensor. At some point, you will likely want to have a conversion between real-world units and “sensor ticks”, but the actual value in your set call will be in those arbitrary ticks.

1 Like

I did change to kSlotIDX, that helped the position.

Motor phase is correct and so is sensor phase.

I am printing motor position and when running, it is in the 1500 range. Motor isn’t stopping at any specific position though.

The github code is updated if you could provide any more guidance.

Turn_POSITION is set to around 4000, or theoretically 4 encoder rotations in the positive direction. If the sensor reading is staying near 1500, then it makes sense that the motor would be trying hard to spin it another 2.5 rotations.

Some of the information makes me a little suspicious of the encoder and the physical setup. Do you happen to have a part number or datasheet for the encoder you are using? If it is operating as the code expects, it should initially have a reading between 0 and 1023 on powering up the robot, and 1 full rotation of the encoder will smoothly increase or decrease the reading by 1024. Is that the behavior you are seeing?

Try setting the target position to a sensor reading that corresponds to a known position. Then, with the robot disabled or powered down, rotate the mechanism about 100-200 units (1/10 to 1/5 of an encoder rotation). After repowering/enabling, the motor should be trying to push towards the original position with about 1-2% throttle (100 units of error * kP of 0.1 / 1023 full throttle). Try setting the mechanism to the same distance to the other side of the original position and confirm that the motor controller is driving the other direction.

1 Like

We’re trying to use the Lamprey Absolute Encoder plugged directly into the Talon Lamprey Absolute Encoder - AndyMark Inc

So after trying what you said I found out a few things. If I turn the encoder by hand the value does increase by that 1024 and when it gets to around 4000 it is doing what it is supposed to be doing. BUT when I actually press the button to control the motor the position value does not go up it stays where it is thus making the motor spin forever.

The AndyMark product page suggests that cutting pins 5 and 7 of the ribbon cable may be required, have you done that? Reading through the Chief Delphi thread for that encoder may also be useful. It looks like some users have had issues with certain motor placements as well, though I’m not sure if that may be a possibility here. In any case, it sounds like the code is fundamentally correct, but there is some other physical/electrical incompatibility going on.

I am not that familiar with the CTRA code base…but make sure you’re using the Lamprey in the same way you would use a potentiometer or MA3 style absolute encoder.

1 Like

I don’t exactly know what you mean by that

1 Like

If I recall the SRX can interface with many different types of sensors.

The Lamprey is an absolute encoder and functions similar to a potentiometer. It provides an analog voltage in proportion to its absolute angle.

This is the opposite of an incremental encoder that provides a digital pulse count of in proportion to its relative angular position.

So make sure your using the correct type of sensor decoding.

You do need to cut pins 5 and 7 and you do need to make sure the cable and port that the cable plugs into are protected from interference.

This is the backside of the connector for the encoder cable. These exposed solder points that close to our Falcon 500, was causing strange signals. Instead of a re-design, we taped some tin foil over these solder points, and the strange signal went away. We did this on 4 different modules, all having the same issue and this fixed the signal on all 4 modules.

Good Luck

1 Like

This is also a good tip…we’ve seen some errors from floating Rx and Tx lines…cutting them from the harness is the best option if you aren’t using them.

Cutting those fully off did fix it. Thank you everyone. Does anyone know how to convert from sensor ticks to angle?