Black Jaguar RS232->CAN - anyone?

Is anyone using the Black Jaguar RS232 to CAN bridge? Just wondering how complete the “CANJaguar for C++” code is and how much risk it is to try that route rather than just hook up old school Gray Jaguars on PWM.

We ran it with 4 Jags hooked up via CAN during the Beta test period. This was using the C++ driver, on our 2009 robot. Only 1 line of code for each Jag had to be changed (substitute constructor).

We did not get the opportunity to use it in a competition environment, however we did use it around the school. During that time, once the initial kinks were worked out to produce the driver version you are now seeing, we got stable performance with the short-term testing we were able to do.

Like any “new” technology, there’s certainly a modest amount of risk involved as it is put through the paces. You’ll want to weigh this against the pros of using CAN over PWM-based control.

Fortunately, if you stay away from the “advanced” features as a necessity in your robot code, changing back to PWM in the event of problems can be simple in robot program (and wiring is, of course, straightforward assuming you still have spare pwm ports and cables around).

The C++ and Java drivers are currently not as fully featured as they could be – they presently support only the voltage-based control mode (so, same mode of control you get with pwm control) plus some of the nifty monitoring functions. I believe the LabVIEW driver is in a similar state.

I would not be surprised if these were augmented in the coming days & weeks, however.

We are also looking at this. I was planning to have one of the students on our team write the functionality for the speed control mode, but I am having a hard time finding the structure for the different CAN messages.

Specifically, looking through the code, it looks like the only trusted messages listed are for enabling different modes and setting their target. In speed control, we would need to know what the messages look like for defining the P and I gains as well as the encoder information.

Unless these can be set in the Jaguar using the BDCOM utility and will stick through power cycles.

Anyone know where I can find this information?

We are trying to use the CAN Bridge with Labview. We have downloaded the sample code and support VIs from SourceForge. We can get the demo code two motor Archade drive to work, but we need to be able to control single motors independently. It appears as if there are no Single motor VIs prebuilt. Are we looking inthe wrong place or do we need to build our own?

Thanks

PGR

The LabVIEW code I just downloaded from FIRST Forge has both a Robot Drive example, and a voltage mode example (with a single motor).

As it turns out, the LabVIEW API is a little farther along. The messages are pretty much all implemented for Voltage, Position, and Speed modes. I still don’t have a good example for the closed loop modes, though. I’ve got a mostly working “position with potentiometer feedback sensor” example working, but that’s it.

I’m working on the C++ API version now.

I couldn’t find this information anywhere, so I used a program to monitor the serial port while BDCOM is running. From this, I modified CANJaguar.cpp and was able to get speed control working (I think). I haven’t added the method to set the number of encoder lines yet, so I don’t know what “units” the speed is in. I haven’t got current mode working. The values sent by DBComm seem to be somewhat random, and the “control” does not seem to work anyway. Current control on the Jaguars with the original firmware (not updated with FRC firmware) seems to work (form bdc-comm-cli.exe) , but the updated ones do not … I don’t know if there is a new command or way of sending the current setpoints … I guess we’ll have to see if they release updated code samples.

You need to add new "case"s for kSpeed to InitJaguar, Set (and Get if you want). In Set, the case I added is: (set speed uses a 16.16 signed fixed point number)
case kSpeed:
messageID = LM_API_SPD_T_SET | m_deviceNumber;
INT32 value32 = (INT32)(outputValue*65536.0 );
((INT32)dataBuffer) = swap32(value32);
dataSize = sizeof(INT32);
break;

I also added a method to set the PID constants:

/**

  • Set the Jaguar PID constants.

  • The inputs are any floating point values

  • @param outputValue The P I and D constants for the motor control.
    */
    void CANJaguar::SetPIDConstants(float kp, float ki, float kd)
    {
    UINT32 messageID;
    UINT8 dataBuffer[8];
    UINT8 dataSize;

    // Send Kp:
    switch(m_controlMode)
    {
    case kCurrent:
    messageID = LM_API_ICTRL_PC | m_deviceNumber;
    break;
    case kSpeed:
    messageID = LM_API_SPD_PC | m_deviceNumber;
    break;
    default:
    ;
    }
    INT32 value = (INT32)(kp*65536.0);
    ((INT32)dataBuffer) = swap32(value);
    dataSize = sizeof(INT32);
    sendMessage(messageID, dataBuffer, dataSize);

    // Send Ki:
    switch(m_controlMode)
    {
    case kCurrent:
    messageID = LM_API_ICTRL_IC | m_deviceNumber;
    break;
    case kSpeed:
    messageID = LM_API_SPD_IC | m_deviceNumber;
    break;
    default:
    ;
    }
    value = (INT32)(ki*65536.0);
    ((INT32)dataBuffer) = swap32(value);
    dataSize = sizeof(INT32);
    sendMessage(messageID, dataBuffer, dataSize);

    // Send Kd:
    switch(m_controlMode)
    {
    case kCurrent:
    messageID = LM_API_ICTRL_DC | m_deviceNumber;
    break;
    case kSpeed:
    messageID = LM_API_SPD_DC | m_deviceNumber;
    break;
    default:
    ;
    }
    value = (INT32)(kd*65536.0);
    ((INT32)dataBuffer) = swap32(value);
    dataSize = sizeof(INT32);
    sendMessage(messageID, dataBuffer, dataSize);

}

Hope this helps. Have fun!

  • Kevin

If you check the SVN server, I’ve commited some additional VIs for implementing the RefNum Registry for CANJaguar references.

This is what I needed! Thanks!

I am assuming this will show up in the source code soon, but we are starting to test it now so I wanted to get something going.

Thanks again,
Matt

Guys,

I’m attempting to add all the commands for speed and position using woodk’s code below and ran into something interesting. If you look at Get() in CANJaguar.cpp:

float CANJaguar::Get()
{
UINT32 messageID;
UINT8 dataBuffer[8];
UINT8 dataSize;
INT32 replyValue32;

switch(m_controlMode)
{
case kPercentVoltage:
	messageID = LM_API_VOLT_SET | m_deviceNumber;
	// Sending set with no data is a request for the last set

The Get() method uses the LM_API_VOLT_SET API definition, but the Set() method uses the LM_API_VOLT_T_SET which is the FIRST trusted message version (I think). Does anyone know why this might be? Or does anyone know if this returns a correct value? I only just set up the CAN stuff yesterday and haven’t gotten knee deep into debugging yet…

In can_proto.h:

//*****************************************************************************
//
// The Luminary Micro Motor Class Control Voltage API definitions.
//
//*****************************************************************************
#define LM_API_VOLT (CAN_MSGID_MFR_LM | CAN_MSGID_DTYPE_MOTOR |
CAN_API_MC_VOLTAGE)
#define LM_API_VOLT_EN (LM_API_VOLT | (0 << CAN_MSGID_API_S))
#define LM_API_VOLT_DIS (LM_API_VOLT | (1 << CAN_MSGID_API_S))
#define LM_API_VOLT_SET (LM_API_VOLT | (2 << CAN_MSGID_API_S))
#define LM_API_VOLT_SET_RAMP (LM_API_VOLT | (3 << CAN_MSGID_API_S))

//##### FIRST BEGIN #####
#ifdef FIRST_FIRMWARE_VERSION
#define LM_API_VOLT_T_EN (LM_API_VOLT | (4 << CAN_MSGID_API_S))
#define LM_API_VOLT_T_SET (LM_API_VOLT | (5 << CAN_MSGID_API_S))
#endif // FIRST_FIRMWARE_VERSION
//##### FIRST END #####

  • Bryce

P.S. Any thoughts on value used in the Position mode for Set() / Get()? In the GetPosition() declaration it states the return value as a float. Does this suggest that position is limited to only one revolution? Also, what data type would one pass to set the encoders?

Ok, I sort of answered my own question. If there’s anyone working on the methods of the API design, check out document SW-RDK-BDC-UG-5570.pdf which is located in the docs folder after installing the “RDK-BDC Firmware Development Package” located here: http://www.luminarymicro.com/products/mdl_bdc.html. You need to register to download the file. I’m not sure if I’m allowed to post it. It explains the command structure and also the data format that the Jags are expecting.

  • Bryce

EDIT!!!: OK, I talked with Joe Hershberger about this issue. Apparently they decided to stick with the code and change the Documentation. I guess the document has not been updated yet. I will keep this posted just in case anyone finds this error as well. So to repeat, the can_proto.h code is correct and should match the FIRST version of the Jag firmware.

woodk,

I might know why your current control is not working… At the section starting at line 119 in can_proto.h there appears to be a bug. If you refer to pages 21 and 22 of the “RDK-BDC Firmware Development Package User’s Guide” they have a table of which bits to use for the API Classes. There are six bits that are assigned for telling the Jag which mode to operate in. The voltage and speed mode bit masks are correct, but the rest are off by one bit. Anyway, this is the code starting at line 119.

#define CAN_API_MC_VOLTAGE 0x00000000
#define CAN_API_MC_SPD 0x00000400
#define CAN_API_MC_POS 0x00000c00
#define CAN_API_MC_ICTRL 0x00001000
#define CAN_API_MC_STATUS 0x00001400
#define CAN_API_MC_CFG 0x00001c00
#define CAN_API_MC_ACK 0x00002000

What I believe to be the correct code is below:

#define CAN_API_MC_VOLTAGE 0x00000000
#define CAN_API_MC_SPD 0x00000400
#define CAN_API_MC_POS 0x00000800
#define CAN_API_MC_ICTRL 0x00000C00
#define CAN_API_MC_STATUS 0x00001000
#define CAN_API_MC_CFG 0x00001400
#define CAN_API_MC_ACK 0x00001800

Try this and see if your current control works. Bits, bits everywhere…

  • Bryce

P.S. THANKS JOE!

Hi Guys,

I think this is the last remaining method to implement speed control (with an encoder). I will test all of this tomorrow to see if it all works (along with woodk’s code). Sorry about all the posts, I’ve been working on this a bit today. The following code is the method to tell the Jag the number of lines of the encoder (per revolution) attached to it. If you want you can just remove the kPosition. I’ve written the functions for that as well by using woodk’s code as a blueprint (and the manual). If one needs to set the number of turns on a potentiometer attached to a motor (position mode only), just replace LM_API_CFG_ENC_LINES with LM_API_CFG_POT_TURNS (that should work).

void SetEncoder(UINT16 encoderLines);

void CANJaguar::SetEncoder(UINT16 encoderLines)
{
UINT32 messageID;
UINT8 dataBuffer[8];
UINT8 dataSize;

switch(m_controlMode)
{
case kPercentVoltage:
	//Do nothing.  An encoder is not used during Voltage mode
	return;
case kSpeed:
case kPosition:
	messageID = LM_API_CFG_ENC_LINES | m_deviceNumber;
	*((UINT16*)dataBuffer) = swap16(encoderLines);
	dataSize = sizeof(UINT16);
	break;
default:
	return;
}

sendMessage(messageID, dataBuffer, dataSize);

}

  • Bryce