RobotDrive and DifferentialDrive both setting motor controllers at different speeds

Our Robot’s code used to use RobotDrive to control the 4 TalonSRXes which control 4 CIMs for driving. Our robot drifts to one side when you are supposed to be driving straight. We already checked the CIMs, power, radio connection, gearbox lubrication and everything. Then, while experimenting, I noticed that half the talons were flashing red rapidly while moving while the other half were solid green. I checked what this means, and it means that those half are moving at a lower speed than the others (and in opposite directions, but that’s just the way the robot is built). I thought it was maybe bad Talons, but then I noticed when I go in reverse, the same thing happens on the other two Talons. I tried moving from RobotDrive to Differential Drive and I still have the same issue, just that now whatever Talons are moving forward flash instead of the ones that are reversing. I also tried using Phoenix Tuner to Factory Rest the settings on all four to default settings. Is this a known issue in either RobotDrive or DifferentialDrive?

Do you have encoders attached so you can have some feedback as to what’s happening with the robot?

Does it happen on blocks as well as on the ground?

Are these 4 Talons plugged into two separate gear boxes, or are they 4 independent motors?

A little more information on your setup would help diagnose the problem.

The DifferentialDrive class negates the input on one side to take care of the motor inversion for one side for you.

Personally, I’m a big fan of having the talons/motors/encoders all in phase with each other. Meaning, when both the right and left Talons are green, the robot moves forward, when they are both red, the robot moves backward. Then, if you have encoders attached, the same, forward means a positive direction, backward means negative direction. It’s also very easy to have one Talon be the master, and the others followers, etc.

Then from there, the driving code becomes very intuitive. You may or may not need to invert the axis value from the controller depending on the type of controller you use, as well as which axis you choose to drive with, but that its simple.

Here’s a thread with basically the same problem, a lot of great advice in there:

  1. No, no encoders yet unfortunately. The only gauge for speed I have is the flickering of the lights.
  2. Yes, I’m testing it lifted right now
  3. the 4 Talons are split, 2 go to one gearbox and 2 go to the other gearbox.

Switching the polarity on the motors is easy enough for me, but like you said, DifferentialDrive inverts it automatically, and I don’t know how to change that. I will read through that post though, thanks.

I just got it, its the dead zone on the controllers. They weren’t outputting 0 when the joystick was centered, and it was ever so slightly turning the bot.

Yes, I suggest calibrating the motor controllers as well.

There’s no real need to use a differential drive if all your stuff is in phase, you can certainly implement an arcade drive or tank drive method on your own and not use it.

For example, here is our VERY MUCH IN PROGRESS DriveTrain code for this year, feel free to use as you see fit.

package frc.robot.subsystems;

import edu.wpi.first.wpilibj.Encoder;
import edu.wpi.first.wpilibj.command.Subsystem;
import frc.robot.RobotMap;
import frc.robot.commands.drivetrain.DefaultDriveCommand;

import com.ctre.phoenix.motorcontrol.ControlMode;
import com.ctre.phoenix.motorcontrol.can.WPI_TalonSRX;

/**
 * Changelog: 
 * 
 */

public class Drivetrain extends Subsystem {

	// Instance variables. There should only be one instance of Drivetrain, but
	// we are
	// assuming the programmer will not accidently create multiple instances

	// Create WPI_TalonSRXs here so we can access them in the future, if we need to
	private WPI_TalonSRX left_motor_master;
	private WPI_TalonSRX left_motor_slave;
	// private WPI_TalonSRXleft_motor3;
	private WPI_TalonSRX right_motor_master;
	private WPI_TalonSRX right_motor_slave;
	// private WPI_TalonSRXright_motor3;

	//sensors
	private Encoder l_encoder;
	private Encoder r_encoder;

	private static final double TALON_RAMP_RATE = 48.0;

	// The two motors mounted as a mirror to one another do not output the
	// exact same force. This value will modify the the dominant side to
	// help the robot drive straight
	private static final double TANK_DRIVE_SCALAR = .94;


	private boolean manualOverride = false;
	private boolean teleopEnabled = false;
	

	// Instantiate all of the variables, and add the motors to their respective
	public Drivetrain() {

	
		left_motor_master = new WPI_TalonSRX(RobotMap.LEFT_TALON_MASTER);
		left_motor_slave = new WPI_TalonSRX(RobotMap.LEFT_TALON_FOLLOWER);
	
		right_motor_master = new WPI_TalonSRX(RobotMap.RIGHT_TALON_MASTER);
		right_motor_slave = new WPI_TalonSRX(RobotMap.RIGHT_TALON_FOLLOWER);

		left_motor_master.setInverted(true);
		left_motor_slave.setInverted(true);

		right_motor_master.setSensorPhase(false);
		
		left_motor_slave.follow(left_motor_master);
		right_motor_slave.follow(right_motor_master);

		// l_encoder = new Encoder(RobotMap.LEFT_ENCODER_PORT1, RobotMap.LEFT_ENCODER_PORT2);
		// r_encoder = new Encoder(RobotMap.RIGHT_ENCODER_PORT1, RobotMap.RIGHT_ENCODER_PORT2);

	}


	// ==FOR TELE-OP
	// DRIVING=======================================================================================
	// For: DefaultDrive Command
	// Sensors: None
	// Description: A basic tank drive method. The two parameters are expected
	// to be within the range -1.0 to 1.0
	// If not, they are limited to be within that range. The parameters will set
	// their respective
	// side of robot to the given value.
	public void tankDrive(double left, double right) {
		if (left > 1.0)
			left = 1.0;
		if (left < -1.0)
			left = -1.0;
		if (right > 1.0)
			right = 1.0;
		if (right < -1.0)
			right = -1.0;

		// Check to see if gear shifting is necessary. if it is, then shift
		// shiftGears();
	}

	// For: DefaultDrive Command
	// Sensors: None
	// Description: A basic arcade drive method. The two parameters are expected
	// to be within the range -1.0 to 1.0
	// If not, they are limited to be within that range. The transitional speed
	// and yaw are combined
	// to be applied to the left motor and right motor. Trans_speed
	// (transitional velocity) will
	// set the robot's forward speed, and yaw (angular velocity) will set the
	// robot turning. Having a
	// combination of the two will make the robot drive on an arc.
	public void arcadeDrive(double trans_speed, double yaw) {
		
		// If yaw is at full, and transitional is at 0, then we want motors to
		// go different speeds.

		trans_speed = normalize(trans_speed);
		yaw = normalize(yaw);

		double left_speed;
		double right_speed;

		// This determines the variable with the greatest magnitude. If the
		// magnitude
		// is greater than 1.0, then divide each variable by the largest so that
		// the largest is 1.0 (or -1.0), and that all other variables are
		// less than that.

		double maxInput = Math.copySign(Math.max(Math.abs(trans_speed), Math.abs(yaw)), trans_speed);

		if(trans_speed>=0.0){
			//Forward
			if(yaw>=0.0){
				//Fwd, Right
				left_speed = maxInput;
				right_speed = trans_speed - yaw;
			} else {
				left_speed = trans_speed + yaw;
				right_speed = maxInput;
			}
		} else {
			//Backward
			if(yaw>=0.0){
				//Bwd
				left_speed = trans_speed + yaw;
				right_speed = maxInput;
			} else {
				left_speed = maxInput;
				right_speed = trans_speed - yaw;
			}
		}

		System.out.println("L: " + left_speed + ", R: " + right_speed);

		left_motor_master.set(ControlMode.PercentOutput, left_speed);
		right_motor_master.set(ControlMode.PercentOutput, right_speed);
	}

	public double normalize(double value){
		if(value>1.0){
			value = 1.0;
		} else if(value<-1.0){
			value = -1.0;
		}
		if(value>-0.01&&value<0.01){
			value = 0.0;
		}
		return value;
	}

	// ==DEFAULT COMMAND AND MOTOR GROUPS
	// CLASS=================================================================
	public void initDefaultCommand() {
		// Allows for tele-op driving in arcade or tank drive
		setDefaultCommand(new DefaultDriveCommand());
	}
}