MD FDCAN communication#

The easiest way to communicate with MD controllers is to use a CANdle device connected to a PC. Even though we are aware some customers want to integrate the MD controllers in their product with minimal setup to reduce the costs and the system’s complexity. This manual will guide you through the process of communicating with MD actuators from your custom CAN master controller.

Hardware requirements#

From firmware version 2.5.0 upwards, MDs are capable of either FDCAN mode communication or CAN2.0 compatibile mode. FDCAN is a preffered protocol to use, as it allows for far greater flexibility and bandwidth. CAN2.0 is supported but not recommended, as the protocol was not optimized for it, and basic operations and control may require multiple CAN frames to be exchanged, significantly reducing the bandwidth, especially with multiple actuators on a single bus.

FDCAN#

The main requirement for the host system is to be equipped with an FDCAN peripheral (either a built-in one or an external one) and an FDCAN transceiver capable of speeds up to 8Mbps. Lower maximum speed transceivers can be used as well, however for the cost of limited update rates. Depending on your custom setup you should be able to integrate a 120 ohm terminating resistor on both ends of your CAN bus.

CAN2.0#

While MD was designed with FDCAN protocol in mind, CAN2.0 compability was introduced. In CAN2.0 mode, the driver can only operate in 1M baudrate, and some registers (that are more than 4 bytes in size) are not available for modification, i.e motorName register. Additionally only some of the Frame Types are supported in this mode - READ_REGISTER_CAN2.0 and WRITE_REGISTER_CAN2.0. In most cases, access in 2.0 mode has to happen 1 register at a time (one register per can frame), with an exception of accessing two U8 type registers. Apart from maximum frame length, the contents of the frames will be the same as in FDCAN version of protocol.

Note

MD controllers can be upgraded to software controlled termination on demand. Please contact us for more information before placing your order.

Communication Structure#

Comminication with MD, happen is a strict Master-Slave structure. The MD itself will never produce a CAN frame by itself, it will only respond to direct commands from a host. Each MD device has configurable CAN ID, that serves as its unique identifier on the CAN bus. There may never be more than one MD with the same CAN ID, as this will lead to conflicts and errors.

All communication with the particular drive will happen only via messeges with particular ID. For example:

Note

Host sends a request (command) to drive with Id 100, the drive will execute the command and respond with a CAN frame that also has the ID of 100

The communication stack is based on a register access using two frames - register read and register write. The list of available registers can be found at the end of this chapter. All fields are little-endian - least significant byte first, and all float fields are 4 bytes long (32 bit) encoded in IEEE-754 standard.

Warning

Wrong access, incorrect data values or other communication errors are not reported explicitly. Command that failed (regardless of the reason), will result in the drive not producing any response. Generally if the drive does not start producing a CAN frame with 100us of the the last bit of the command, the host may consider the command has failed.

Frame Structure#

All frames (FDCAN and CAN2.0) are composed in the same fasion. The first byte is a Frame Type, then a padding byte, followed by the contents of a message.

Message contents are similar in both read and write operations. They follow a pattern of repeating sequence: register id (2 bytes) and register value (1-24 bytes depending on a register). The number of registers to be accessed is only limited by a size of message - 64 bytes for FDCAN, and 8 bytes for CAN2.0.

BYTE 0 BYTE 1 BYTE 2-3 BYTE 4-X BYTE X+1-X+2 BYTE X+4-X+Y ...
FRAME ID PADDING (0x00) REG ID 1 VALUE 1 REG ID 2 VALUE 2 ...

For example, a frame that would read a value of the current position, velocity and torque from a drive, would, have a length of 20 bytes, and look like the following:

BYTE 0 BYTE 1 BYTE 2-3 BYTE 4-7 BYTE 8-9 BYTE 10-13 BYTE 14-15 BYTE 16-19
FRAME ID PADDING (0x00) regId - mainEncoderPosition PADDING regId - mainEncoderVelocity PADDING regId - motorTorque PADDING
0x41 0x00 0x0062 0x00 00 00 00 0x0063 0x00 00 00 00 0x0064 0x00 00 00 00

Frame Types#

Although there are basically only two possible variants of frames - read and write register - the frames can trigger different behaviours, apart of reading and writing. Here is a brief description of the frame behaviours by their id:

Frame ID Name Description
0x40 WRITE_REGISTER_LEGACY performs write operation, and makes the drive respond with legacy response. This is sometimes usefull in high frequency control loops, to minimize number of frames exchanged. For frame contents, refer to Write Register Frame .
0x41 READ_REGISTER performs read operation, and responds with state of the registers. Refer to Read Register Frame
0x42 WRITE_REGISTER performs write operation, and responds with state of the registers AFTER operation. Usefull for verification of write operation. For more info, refer to Write Register Frame
0x43 READ_REGISTER_CAN2.0 performs read operation, and responds with state of the registers. Works same as Read Register Frame , but is limited to 8 bytes and produces CAN2.0 compatibile response.
0x44 WRITE_REGISTER_CAN2.0 performs write operation, and responds with state of the registers AFTER operation. Usefull for verification of write operation. Works same as Write Register Frame , but is limited to 8 bytes and produces CAN2.0 compatibile response.
0x0A LEGACY_RESPONE RESPONSE ONLY. A response produced as a result of some frames. Contains data, most commonly required in fast control loops - more info here.

Write register frame#

Write register frame is used to modify values of the user-modifiable registers. Only registers with write access can be modified.

FRAME NAME DRIVE ID LENGTH BYTE 0 [ID] BYTE 1 BYTE 2-3 BYTE 4-X BYTE X+1-X+2 BYTE X+4-X+Y
WRITE_REGISTER 10-2000 X (64 max) 0x42 0x00 reg ID value reg ID value

Params:

  • regID (uint16_t) - first register ID (please see the end of this section)

  • value (uint8_t/uint16_t/uint32_t/float/char[]) - first register value to be written

  • regID (uint16_t) - second register ID (please see the end of this section)

  • value (uint8_t/uint16_t/uint32_t/float/char[]) - second register value to be written

  • … (up to 64 bytes total)

EXAMPLE Write target position and velocity

Command, send from host to MD:

BYTE 0 BYTE 1 BYTE 2-3 BYTE 4-7 BYTE 8-9 BYTE 10-13
FRAME ID PADDING (0x00) regId - targetPosition (float) 0.25 regId - targetVelocity (float) -7.4
0x42 0x00 0x0150 0x3E 80 00 00 0x0151 0xC0 EC CC CD

Which in raw HEX is: 0x42 00 01 50 3E 80 00 00 01 51 C0 EC CC CD

Response, send from MD to Host:

BYTE 0 BYTE 1 BYTE 2-3 BYTE 4-7 BYTE 8-9 BYTE 10-13
FRAME ID PADDING (0x00) regId - targetPosition (float) 0.25 regId - targetVelocity (float) -7.4
0x42 0x00 0x0150 0x3E 80 00 00 0x0151 0xC0 EC CC CD

Which in raw HEX is: 0x42 00 01 50 3E 80 00 00 01 51 C0 EC CC CD

Read Register Frame#

Read register command is used to retrieve certain register values. The actuator will respond with a frame consisting of the addresses and values of the registers issued in the master request. The master request should have the following form:

FRAME NAME DRIVE ID LENGTH BYTE 0 [ID] BYTE 1 BYTE 2-3 BYTE 4-X BYTE X+1-X+2 BYTE X+4-X+Y
READ_REGISTER 10-2000 X (64 max) 0x41 0x00 reg ID 0x00 reg ID 0x00

When all read operations succeed the 0x00 fields will be filled with appropriate register data when transmitted back to master by the MDxx controller.

FRAME NAME DRIVE ID LENGTH BYTE 0 [ID] BYTE 1 BYTE 2-3 BYTE 4-X BYTE X+1-X+2 BYTE X+4-X+Y
Response to register read 10-2000 X (64 max) 0x41 0x00 reg ID reg value reg ID reg value

EXAMPLE Read MD status and position

Command, send from host to MD:

BYTE 0 BYTE 1 BYTE 2-3 BYTE 4-5 BYTE 6-7 BYTE 8-11
FRAME ID PADDING (0x00) regId - quickStatus PADDING (2 bytes) regId - mainEncoderPosition PADDING (4 bytes)
0x41 0x00 0x0805 0x00 00 0x0062 0x00 00 00 00

Which in raw HEX is: 0x41 00 08 05 00 00 00 62 00 00 00 00

Response, send from MD to Host:

BYTE 0 BYTE 1 BYTE 2-3 BYTE 4-5 BYTE 6-7 BYTE 8-11
FRAME ID PADDING (0x00) regId - quickStatus status (u16) regId - mainEncoderPosition 16.74 (float)
0x41 0x00 0x0805 0x80 00 0x0062 0x41 85 EB 85

Which in raw HEX is: 0x41 00 08 05 80 00 00 62 41 85 EB 85

Legacy response#

BYTE 0 BYTE 1-2 BYTE 3 BYTE 4-7 BYTE 8-11 BYTE 12-15 BYTE 16-19 BYTE 20-23
NAME FRAME ID QUICK STATUS MOTOR TEMPERATURE MAIN ENCODER POSITION MAIN ENCODER VELOCITY MOTOR TORQUE OUTPUT ENCODER POSITION OUTPUT ENCODER VELOCITY
TYPE uint8_t uint16_t uint8_t [*C] float [rad] float [rad/s] float [Nm] float [rad] float [rad/s]
VALUE 0x0A 0x0000 - 0xFFFF 0 - 255 - - - - -

Available registers#

reg name address read/write size limits description
canId 0x001 RW uint32_t [10-2000] FDCAN bus id number
canBaudrate 0x002 RW uint32_t [1e6;2e6;5e6;8e6] FDCAN bus baudrate
canWatchdog 0x003 RW uint16_t [0-2500] FDCAN bus watchdog period in ms
canTermination 0x004 RW uint8_t [0-1] CAN termination (available upon request)
motorName 0x010 RW char[24] - motor name
motorPolePairs 0x011 RW uint32_t [2;225] motor pole pair count
motorKt 0x012 RW float >0 motor torque constant
motorKt_a 0x013 RW float >0 optional parameter for phase specific torque constant
motorKt_b 0x014 RW float >0 optional parameter for phase specific torque constant
motorKt_c 0x015 RW float >0 optional parameter for phase specific torque constant
motorIMax 0x016 RW float [1 - peak controller current] maximum phase current
motorGearRatio 0x017 RW float - actuator gear ratio (ex 2:1 should be 0.5) <1 - reducer >1 - multiplier
motorTorqueBandwidth 0x018 RW uint16_t [50-2500] torque bandwidth in Hz
motorFriction 0x019 RO float32 - UNUSED
motorStiction 0x01A RO float32 - UNUSED
motorResistance 0x01B RO float [5mOhm-20Ohm] motor resistance in d axis
motorInductance 0x01C RO float [5nH-100mH] motor inductance in d axis
motorKV 0x01D RW uint16_t - motor KV rating [RPM/V]
motorCalibrationMode 0x01E RW uint8_t [0;1] FULL = 0, NOPPDET = 1
motorThermistorType 0x01F RW uint8_t - -
outputEncoder 0x020 RW uint8_t [0;1;2;3] NONE = 0, ME_AS_CENTER = 1, ME_AS_OFFAXIS = 2, MB053SFA17BENT00 = 3, CM_OFFAXIS = 4, M24B_CENTER = 5, M24B_OFFAXIS = 6
outputEncoderDir 0x021 RW uint8_t 0 RESERVED
outputEncoderDefaultBaud 0x022 RW uint32_t 115200 optional parameter for setting default output encoder baudrate
outputEncoderVelocity 0x023 RO float - output encoder velocity in rad/s (calculated in a 5kHz loop)
outputEncoderPosition 0x024 RO float - output encoder position in rad (read in 5kHz loop)
outputEncoderMode 0x025 RW uint8_t [0;1;2;3;4] NONE = 0, STARTUP = 1, MOTION = 2, REPORT = 3, MAIN = 4
outputEncoderCalibrationMode 0x026 RW uint8_t [0;1] FULL = 0, DIRONLY = 1
motorPosPidKp 0x030 RW float - position PID proportional gain
motorPosPidKi 0x031 RW float - position PID integral gain
motorPosPidKd 0x032 RW float - position PID derivative gain
motorPosPidWindup 0x034 RW float - position PID integral windup limit
motorVelPidKp 0x040 RW float - velocity PID proportional gain
motorVelPidKi 0x041 RW float - velocity PID integral gain
motorVelPidKd 0x042 RW float - velocity PID derivative gain
motorVelPidWindup 0x044 RW float - velocity PID integral windup limit
motorImpPidKp 0x050 RW float - impedance PD proportional gain
motorImpPidKd 0x051 RW float - impedance PD derivative gain
mainEncoderVelocity 0x062 RO float - main encoder velocity in rad/s (calculated in a 40kHz loop)
mainEncoderPosition 0x063 RO float - main encoder position in rad (read in 40kHz loop)
motorTorque 0x064 RO float - motor output shaft torque in Nm (read in 40kHz loop)
runSaveCmd 0x080 WO uint8_t other than 0 to run save non-volatile memory
runTestMainEncoderCmd 0x081 WO uint8_t other than 0 to run runs main encoder test routine
runTestOutputEncoderCmd 0x082 WO uint8_t other than 0 to run runs output encoder test routine
runCalibrateCmd 0x083 WO uint8_t other than 0 to run runs main calibration routine
runCalibrateOutputEncoderCmd 0x084 WO uint8_t other than 0 to run runs output encoder calibration routine
runCalibratePiGains 0x085 WO uint8_t other than 0 to run runs current PI loop calibration routine
runRestoreFactoryConfig 0x087 WO uint8_t other than 0 to run reverts config to factory state
runReset 0x088 WO uint8_t other than 0 to run resets the controller
runClearWarnings 0x089 WO uint8_t other than 0 to run clears all warnings
runClearErrors 0x08A WO uint8_t other than 0 to run clears non-critical errors
runBlink 0x08B WO uint8_t other than 0 to run blinks onboard LEDs
runZero 0x08C WO uint8_t other than 0 to run sets new zero position
runCanReinit 0x08D WO uint8_t other than 0 to run reinitializes can peripheral
calOutputEncoderStdDev 0x100 RO float - output encoder test result (standard deviation)
calOutputEncoderMinE 0x101 RO float - output encoder test result (min error)
calOutputEncoderMaxE 0x102 RO float - output encoder test result (max error)
calMainEncoderStdDev 0x103 RO float - main encoder test result (standard deviation)
calMainEncoderMinE 0x104 RO float - main encoder test result (min error)
calMainEncoderMaxE 0x105 RO float - main encoder test result (max error)
positionLimitMax 0x110 RW float - maximum valid position
positionLimitMin 0x111 RW float - minimum valid position
maxTorque 0x112 RW float - maximum torque
maxVelocity 0x113 RW float - maximum velocity
maxAcceleration 0x114 RW float - maximum acceleration
maxDeceleration 0x115 RW float - maximum deceleration
profileVelocity 0x120 RW float - profile velocity
profileAcceleration 0x121 RW float - profile acceleration
profileDeceleration 0x122 RW float - profile deceleration
quickStopDeceleration 0x123 RW float - quick stop deceleration in case of a non-critical error
positionWindow 0x124 RW float - position window within position is considered to be reached
velocityWindow 0x125 RW float - velocity window within velocity is considered to be reached
motionModeCommand 0x140 WO uint8_t - commands a motion mode change: IDLE = 0x00, POSITION_PID = 0x01, VELOCITY_PID = 0x02, RAW_TORQUE = 0x03, IMPEDANCE = 0x04, POSITION_PROFILE = 0x07, VELOCITY_PROFILE = 0x08
motionModeStatus 0x141 RO uint8_t - shows the currently set motion mode
state 0x142 RW uint16_t - returns the internal state machine state of the controller
targetPosition 0x150 RW float - sets target position in rad
targetVelocity 0x151 RW float - sets target velocity in rad/s
targetTorque 0x152 RW float - sets target torque in Nm
userGpioConfiguration 0x160 RW uint8_t - 0 - OFF, 1 - AUTO-BRAKE, 2 - GPIO INPUT
userGpioState 0x161 RO uint16_t - GPIO input state
reverseDirection 0x600 RW uint8_t - used to change the direction of the main encoder when using other encoders than the onboard one. Always recalibrate after changing this setting
shuntResistance 0x700 RO float [0.001 - 0.01] Current sense resistor value. Setting this register to a value that is not coherent with the hardware may damage the controller. In this cases warranty is not respected.
buildDate 0x800 RO uint32_t - software build date
commitHash 0x801 RO char[8] - commit hash
firmwareVersion 0x802 RO uint32_t - -
hardwareVersion 0x803 RO uint8_t - -
bridgeType 0x804 RO uint8_t - type of the mosfet driver
quickStatus 0x805 RO uint16_t - quick status vector
mosfetTemperature 0x806 RO float - power stage temperature
motorTemperature 0x807 RO float - motor temperature (if thermistor is mounted)
motorShutdownTemp 0x808 RW uint8_t - temperature at which the MD series motor controller will enter IDLE mode
mainEncoderErrors 0x809 RO uint32_t - main encoder errors
outputEncoderErrors 0x80A RO uint32_t - output encoder errors
calibrationErrors 0x80B RO uint32_t - calibration errors
bridgeErrors 0x80C RO uint32_t - bridge errors
hardwareErrors 0x80D RO uint32_t - hardware errors
communicationErrors 0x80E RO uint32_t - communication errors
motionErrors 0x810 RO uint32_t - motion errors