Need help solving the CAN mystery

I’m one of the team mentors for FRC 4386.

We would like to use CAN Talon SRX controllers this year. We’ve always used PWM previously and I just can’t seem to get my head wrapped around how CAN works.

Specifically I’m having trouble even just declaring motor controllers and the setup and initialization code in the drivetrain subsystem. :confused:

I’ve searched and just can’t seem to find any code examples or documentation on how to get off the starting line, so to speak. If anyone out here can help me find some code examples or a good explanation of implementing CAN at the code level it would be greatly appreciated! We are also planning to use a Mechanum drive so any examples that you can point me to using that would be extra helpful.

Thanks!

This is what I taught the beginner programmers today with the standard Iterative robot provided by FIRST using two CAN Talons as the drive base. The code basically created one joystick intending to do Arcade Drive, two CAN Talons for the left and the right wheels and a drive base taking the two wheels. Then in TeleOp, you just call Arcade Drive and give it the joystick. That’s it. Basically, I have added 5 lines to the Iterative Robot sample code and have a drivable robot base.
Note that the parameters passed to the CANTalon constructors are CAN IDs. In the code below, the left wheel has ID 3 and right wheel ID 4. CAN Talon motor controllers are connected to the CAN bus which is basically just two wires. All CAN devices tap onto these two wires. So when talking to them, you need to address the device by its CAN ID. So you need to set up each of the CAN Talon controller with its unique ID generally in the range of 1 to 63 (don’t use 0 because that’s the default ID came from the manufacturer). You need to use the web interface of the RoboRIO to change the CAN ID of each CAN Talon. You need to do this just once and the ID is saved in non-volatile memory in the controller.


package org.usfirst.frc.team492.robot;

import com.ctre.CANTalon;

import edu.wpi.first.wpilibj.IterativeRobot;
import edu.wpi.first.wpilibj.Joystick;
import edu.wpi.first.wpilibj.RobotDrive;
import edu.wpi.first.wpilibj.smartdashboard.SendableChooser;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;

/**
 * The VM is configured to automatically run this class, and to call the
 * functions corresponding to each mode, as described in the IterativeRobot
 * documentation. If you change the name of this class or the package after
 * creating this project, you must also update the manifest file in the resource
 * directory.
 */
public class Robot extends IterativeRobot {
	final String defaultAuto = "Default";
	final String customAuto = "My Auto";
	String autoSelected;
	SendableChooser<String> chooser = new SendableChooser<>();
	Joystick stick = new Joystick(0);
	CANTalon leftWheel = new CANTalon(3);
	CANTalon rightWheel = new CANTalon(4);
    RobotDrive myRobot = new RobotDrive(leftWheel, rightWheel);

	/**
	 * This function is run when the robot is first started up and should be
	 * used for any initialization code.
	 */
	@Override
	public void robotInit() {
		chooser.addDefault("Default Auto", defaultAuto);
		chooser.addObject("My Auto", customAuto);
		SmartDashboard.putData("Auto choices", chooser);
		
	}

	/**
	 * This autonomous (along with the chooser code above) shows how to select
	 * between different autonomous modes using the dashboard. The sendable
	 * chooser code works with the Java SmartDashboard. If you prefer the
	 * LabVIEW Dashboard, remove all of the chooser code and uncomment the
	 * getString line to get the auto name from the text box below the Gyro
	 *
	 * You can add additional auto modes by adding additional comparisons to the
	 * switch structure below with additional strings. If using the
	 * SendableChooser make sure to add them to the chooser code above as well.
	 */
	@Override
	public void autonomousInit() {
		autoSelected = chooser.getSelected();
		// autoSelected = SmartDashboard.getString("Auto Selector",
		// defaultAuto);
		System.out.println("Auto selected: " + autoSelected);
	}

	/**
	 * This function is called periodically during autonomous
	 */
	@Override
	public void autonomousPeriodic() {
		switch (autoSelected) {
		case customAuto:
			// Put custom auto code here
			break;
		case defaultAuto:
		default:
			// Put default auto code here
			break;
		}
	}

	/**
	 * This function is called periodically during operator control
	 */
	@Override
	public void teleopPeriodic() {
	    myRobot.arcadeDrive(stick);
	}

	/**
	 * This function is called periodically during test mode
	 */
	@Override
	public void testPeriodic() {
	}
}

BTW, here is an example for mecanum drive base. 8 lines total added to the standard Iterative robot code.


package org.usfirst.frc.team492.robot;

import com.ctre.CANTalon;

import edu.wpi.first.wpilibj.IterativeRobot;
import edu.wpi.first.wpilibj.Joystick;
import edu.wpi.first.wpilibj.RobotDrive;
import edu.wpi.first.wpilibj.smartdashboard.SendableChooser;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;

/**
 * The VM is configured to automatically run this class, and to call the
 * functions corresponding to each mode, as described in the IterativeRobot
 * documentation. If you change the name of this class or the package after
 * creating this project, you must also update the manifest file in the resource
 * directory.
 */
public class Robot extends IterativeRobot {
	final String defaultAuto = "Default";
	final String customAuto = "My Auto";
	String autoSelected;
	SendableChooser<String> chooser = new SendableChooser<>();
	Joystick leftStick = new Joystick(0);
	Joystick rightStick = new Joystick(1);
	CANTalon leftFrontWheel = new CANTalon(3);
	CANTalon rightFrontWheel = new CANTalon(4);
	CANTalon leftRearWheel = new CANTalon(5);
	CANTalon rightRearWheel = new CANTalon(6);
    RobotDrive myRobot = new RobotDrive(leftFrontWheel, leftRearWheel, rightFrontWheel, rightRearWheel);

	/**
	 * This function is run when the robot is first started up and should be
	 * used for any initialization code.
	 */
	@Override
	public void robotInit() {
		chooser.addDefault("Default Auto", defaultAuto);
		chooser.addObject("My Auto", customAuto);
		SmartDashboard.putData("Auto choices", chooser);
		
	}

	/**
	 * This autonomous (along with the chooser code above) shows how to select
	 * between different autonomous modes using the dashboard. The sendable
	 * chooser code works with the Java SmartDashboard. If you prefer the
	 * LabVIEW Dashboard, remove all of the chooser code and uncomment the
	 * getString line to get the auto name from the text box below the Gyro
	 *
	 * You can add additional auto modes by adding additional comparisons to the
	 * switch structure below with additional strings. If using the
	 * SendableChooser make sure to add them to the chooser code above as well.
	 */
	@Override
	public void autonomousInit() {
		autoSelected = chooser.getSelected();
		// autoSelected = SmartDashboard.getString("Auto Selector",
		// defaultAuto);
		System.out.println("Auto selected: " + autoSelected);
	}

	/**
	 * This function is called periodically during autonomous
	 */
	@Override
	public void autonomousPeriodic() {
		switch (autoSelected) {
		case customAuto:
			// Put custom auto code here
			break;
		case defaultAuto:
		default:
			// Put default auto code here
			break;
		}
	}

	/**
	 * This function is called periodically during operator control
	 */
	@Override
	public void teleopPeriodic() {
	    myRobot.mecanumDrive_Cartesian(leftStick.getX(), rightStick.getY(), rightStick.getTwist(), 0.0);
	}

	/**
	 * This function is called periodically during test mode
	 */
	@Override
	public void testPeriodic() {
	}
}

This was exactly what I needed to finally understand CAN. Thanks to MikeTS for your response and your code samples! We are using a mechanum drive this year so your code especially for that was extremely helpful!

I’m glad you made progress, but isn’t that basically section 1 of the Talon SRX Software Reference Manual?

Were our github examples helpful? Here’s a java one with RobotDrive and many talons.

And section 3.4 in the software reference manual specifically calls out how to use RobotDrive.