Scanning for motor type

Okay I have no idea if this is at all possible but the goal here would be to create a self sufficient drive train object/subsystem in Robot where in the DriveTrain class is can tell if it’s supposed to be controlled with CANTalons or Victors. Is there a way to scan CAN ports to see if there is something is connected to that port so I can check if the ports our team has dedicated to CAN drive train devices are occupied?

Man - I want whatever you’ve got.

Alright in all seriousness - can you be more specific about what you are trying to accomplish? It’s definitely possible to enumerate all the devices on the CAN bus but determining what motor you have attached on the other side is… difficult, if not impossible for all practical purposes.

Yeah sure!

What I’m trying to here is basically just be able to push the same code onto two separate bots, one with Victors and one with Talons and have them both work, that’s end goal. I’m thinking of just doing a check on if there are Talons connected to specific ports and if they are, creating a Talon based subsystem and if there aren’t create a Victor based subsystem.

That makes more sense. You could setup the two robots to use different IDs for the CAN devices and then perform a check for only specific IDs and act accordingly.

If all you want to do is tell which of two robots the code is running on, the really easy way to do it is to get one of those 0.1" pin jumpers and install it on one of the DIO ports of one of the robots, connecting the data pin to ground; do not install the jumper on the other robot, or use it to connect the data pin to +5V. Then, when you do a digital read that DIO pin, you’ll get zero on the one with the pin and one on the one without. Once you’ve determined which robot you’re on, some if then {} else {} statements in the constructors should do the rest.

Edit: I recall a few years ago we did this by checking the MAC address of the radio, though this was just to determine which set of calibration constants to use. Do not recommend; confusion ensued when we had radio problems and did some swaps to figure out what the problem was.

Yeah, I get the concept I just don’t know how to perform the check to see if a device ID/port is occupied?

For what I was proposing - I think you’ll need to consult the CTRE docs and APIs. GetDeviceID and GetDeviceNumber seem promising.

For what Gus is suggesting, you’ll need to use the wpilib docs and check the value of the signal on the port.

Try{
//code for talons}

Catch{
//code for victors}

If your device is on PWM or Relay ports, there is no feedback path to determine if there is a device on the other end, much less what it is. So, if you mean Talon SRs or Victor SPs or SRXs or SPXs operating in PWM mode, no. However, if you are using these in PWM mode, the practical difference is minimal to nonexistent.

If you are referring to SRXs and SPXs, controlled through CAN, then yes there is. I did not see anything in the WPIlib or CTRE documentation which allows you to access the raw CAN updates from each device, but the method Marcus suggested should work; while I haven’t found it documented, the TalonSRX() constructor will likely throw an exception if there are no Talon SRX devices at that ID on the CAN bus.

Another option would be to use the MAC address of the RIO, similarly to what 254 does. Store the practice robot’s MAC in code somewhere, and on robot init do a simple if/else to set a global flag in your code. This way you can also use this flag for other decisions in your code (different PID gains for each robot, etc.)

Checking for the practice robot’s MAC address ensures that no matter what happens at comp (short of switching in your practice RIO), you will always default to comp bot settings.

In regards to the motor controllers, if you are using Victor SPXs, this should be easy, as both SRXs and SPXs extend the common base class ‘BaseMotorController’, so simply set your variable types to that and instantiate the objects based on the flag you set earlier.

Here’s a short example in Java:


//in your Robot class

public static boolean IS_PRACTICE_BOT = false;
private static final String PRACTICE_MAC = "mac_address_here";

private static String getMacAddress() {
    //Insert 254s code here
}

public void robotInit() {
    IS_PRACTICE_BOT = getMacAddress().equals(PRACTICE_MAC);
}

//in your Subsytem class

private BaseMotorController left = (Robot.IS_PRACTICE_BOT) ? new VictorSPX(0) : new TalonSRX(0);

//etc

This solution also means that your IDs do not have to match between the practice and comp robots.

1 Like

Well, we’ve done a RIO swap at competition also, though not as often as a radio swap.

Edit:

At that time we only had two RIOs, so the one we swapped in was the one which was normally on the practice robot.

If you check for the practice robot’s MAC address and assume everything else is the competition robot, you only have to deal with changing code if you switch the practice robot’s RIO. And if you’re working on your practice robot, you’re definitely not at competition so you should have time to look up the new MAC address.

It will not; however you will get warnings about not being able to read the firmware version from the Talon SRX in the DS logs. There is a corresponding ErrorCode for that though, but you really don’t want to allocate resources for devices that don’t exist on your robot. The CTRE Phoenix API does not have any way of deallocating resources.

Some sort of global IS_PRACTICE_BOT flag and declaring variables as BaseMotorControllers seems like a reasonable way to do this.

The best solution would be to just set an environment variable flag on the practice bot, then look for that flag when your program starts. If it’s present, then you know you’re running on the practice bot; otherwise, you can reasonably assume that you’re running on the competition robot.

This has the advantage of not needing to keep track of MAC addresses in your code, and makes it easier to switch roboRIOs. Just update .bashrc if you switch the roboRIO on the practice robot. Switching the roboRIO on the competition robot will be fine since the environment variable is only present on the practice robot.

We’ve use the jumper on the MXP method on our practice bots for the past few years. If you want to see an example in Java check out our 2017 code. Basically boils down to the following inside Robot.java


private static DigitalInput practiceBot;
practiceBot = new DigitalInput(RobotMap.PRACTICE_BOT_JUMPER);. //PRACTICE_BOT_JUMPER is set to the number 24 

/**
 * Returns the status of DIO pin 24 
 *
 * @return true if this is the practice robot
 */
public static boolean isPracticeRobot() {
	return !practiceBot.get();
}

//Elsewhere in code when you want to do something special on the practice robot...
if (Robot.isPracticeRobot()) {
    //Something to do on 5he practice bot
} else {
    //something to do on the competition bot
}

Then on the practice bot we place a 0.1" jumper across pin 32 (DIO channel 24 in WPIlib) and pin 30 (ground) on the MXP. See attached image for identification of pins.
0.1" jumper: https://www.adafruit.com/product/3525 - not recommending purchase just linking for image - you likely have these from KOP or on an old motor controller

This has worked out quite well for us over the past few years, only the practice bot needs special waiting, any RIO can be used as the competition one with no special wiring changes needed.

https://github.com/Team2168/2017_Main_Robot/blob/develop/src/org/team2168/Robot.java


Clever. I like it.

I’ll continue my usb-drived themed responses with an extension of Gus’s idea:

Get a bunch of tiny USB drives and number them 1, 2, 3, 4, 5, … On each drive, put a file in the root directory named “I_AM_ROBOT_NUMBER_1.txt” and “I_AM_ROBOT_NUMBER_2.txt” and so on.

At runtime in the code, check for the presence of one of these files, and choose your behavior accordingly.

Same advantage of one codebase, multiple cal sets, and an easy way to assign which robot has which behavior even when hardware swaps.

Variations on this technique are actually quite common in industry.