Log in

View Full Version : Refnum like interface for CANJaguars


biojae
31-05-2010, 01:05
*Note that I have not tested this yet*

After playing around with Labview a little bit, I learned that I liked the idea of Refnums (identifier strings that can be used to describe and identify objects).

And after using Java and CAN on this years robot, I wanted something that would not use the bus for every single call to the getter methods.

So, I made a simple class that uses a Hashtable (Stores the instances of CANJaguar with a unique and descriptive name (like a refnum)) and a TimerTask that updates the data in the local cache at around 50 hertz.

Here is a simple example that uses the class (a simple arcade drive teleoperated)


package edu.wpi.first.wpilibj.templates;

import edu.wpi.first.wpilibj.CAN.CANBus;
import edu.wpi.first.wpilibj.IterativeRobot;
import edu.wpi.first.wpilibj.Joystick;


public class RobotTemplate extends IterativeRobot {

CANBus bus = new CANBus();

Joystick arcade = new Joystick(1);

public void robotInit()
{
bus.addJaguar("LeftDrive", 2);
bus.addJaguar("RightDrive", 3);
}


public void autonomousPeriodic() {

}

public void teleopPeriodic() {

// Arcade drive implementation
double speed = -arcade.getY();
double turn = arcade.getX();

double left = speed + turn;
double right = speed - turn;

if(left > 1){ left = 1;}
else if(left < -1){ left = -1;}

if(right > 1){ right = 1;}
else if(right < -1){ right = -1;}
// End arcade drive implementation

bus.setPercentOutputVoltage("LeftDrive", left);
bus.setPercentOutputVoltage("RightDrive", right);
}

}


and here is the actual class (Note that I made a slight change to the JaguarCANProtocol class, I added public static final int LM_STATUS_FAULT_BUSERR = 0xFF; so that I could signal to the main execution loop that there was an error in either transmission or reception.):


/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package edu.wpi.first.wpilibj.CAN;

import java.util.Timer;
import edu.wpi.first.wpilibj.util.UncleanStatusException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.TimerTask;

/**
* Keeps track of all CANJaguar instances on CAN bus using unique Names.
* Use this to access information about a jaguar without acessing the bus directly
* This is a local cache so that data from the bus is not accessed except by one thread.
* Will update the data around 50 times a second depending on the # of devices
* on the bus, and on the device used to cummunocate with the Jaguars (ie 2CAN or black jag)
*
* As far as controlling the JAguar goes, this only supports the Voltage control mode (for now)
* If other modes are needed, then use the getjaguar method.
* (Note that controlling the jaguar outside of this class will not provide any exception handling)
*
* @author biojae
*/
public class CANBus
{
// Keep an instance of each CANJaguar, (Generics not supported by squawk)
private Hashtable devices = new Hashtable();
// Keep a local copy of status information on each jaguar so as to reduce data throughput on CAN
private Hashtable statuses = new Hashtable();
//Update the device information ~50 times a second (depending on # of devices)
private Timer updateThread;

public CANBus()
{
TimerTask update = new TimerTask()
{
public void run()
{
for (Enumeration name = devices.keys() ; name.hasMoreElements() ;)
{
String jagName = name.nextElement().toString();
CANJaguar currentJag = (CANJaguar) devices.get(jagName);
CANJaguarInfo currentInfo = (CANJaguarInfo) statuses.get(jagName);
try{
currentJag.set(currentInfo.outputPercentVoltage);

currentInfo.BusVoltage = currentJag.getBusVoltage();
currentInfo.OutVoltage = currentJag.getOutputVoltage();
currentInfo.Temperature = currentJag.getTemperature();
currentInfo.outCurrent = currentJag.getOutputCurrent();
currentInfo.position = currentJag.getPosition();
currentInfo.speed = currentJag.getSpeed();
currentInfo.faults = currentJag.getFaults();
}catch(UncleanStatusException errorOnBus)
{
errorOnBus.printStackTrace();
currentInfo.faults = JaguarCANProtocol.LM_STATUS_FAULT_BUSERR;
}
statuses.put(jagName, currentInfo);
}
}
};

updateThread = new Timer();
updateThread.scheduleAtFixedRate(update, 0, 20);

}

public void setPercentOutputVoltage(String name, double set)
{
if(statuses.contains(name))
{
((CANJaguarInfo)statuses.get(name)).outputPercentV oltage = set;
}
}

public boolean addJaguar(String name, int ID)
{
try{
devices.put(name, new CANJaguar(ID));
statuses.put(name, new CANJaguarInfo());
}catch(UncleanStatusException CANBusError)
{
devices.remove(name);
statuses.remove(name);
CANBusError.printStackTrace();
return false;
}
return true;
}

public double getTemperature(String name)
{
if(devices.contains(name))
{
return ((CANJaguarInfo)statuses.get(name)).Temperature;
}
return -1;
}

public double getBusVoltage(String name)
{
if(devices.contains(name))
{
return ((CANJaguarInfo)statuses.get(name)).BusVoltage;
}
return -1;
}

public double getOutputVoltage(String name)
{
if(devices.contains(name))
{
return ((CANJaguarInfo)statuses.get(name)).OutVoltage;
}
return -1;
}

public double getOutpuCurrent(String name)
{
if(devices.contains(name))
{
return ((CANJaguarInfo)statuses.get(name)).outCurrent;
}
return -1;
}

public double getPosition(String name)
{
if(devices.contains(name))
{
return ((CANJaguarInfo)statuses.get(name)).position;
}
return -1;
}

public double getSpeed(String name)
{
if(devices.contains(name))
{
return ((CANJaguarInfo)statuses.get(name)).speed;
}
return -1;
}

public short getFaults(String name)
{
if(devices.contains(name))
{
return ((CANJaguarInfo)statuses.get(name)).faults;
}
return -1;
}

public CANJaguar getJaguar(String name)
{
if(devices.contains(name))
{
return (CANJaguar) devices.get(name);
}
return null;
}
}