Skip to content

Commit dbc95b1

Browse files
committedSep 18, 2023
Add CAN source files
1 parent 837c6b3 commit dbc95b1

15 files changed

+1756
-0
lines changed
 

‎huron_driver/can/BUILD.bazel

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
cc_library(
2+
name = "can",
3+
srcs = ["can_simple_master.cc", "huron_canbus.cc"],
4+
hdrs = ["ODriveEnums.h", "can_helpers.h", "canbus.h", "can_simple_master.h", "huron_canbus.h"],
5+
deps = ["//huron_driver/config:config"],
6+
visibility = ["//examples/test_can:__pkg__"]
7+
)

‎huron_driver/can/ODriveEnums.h

+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
#ifndef ODriveEnums_h
2+
#define ODriveEnums_h
3+
4+
/* TODO: This file is dangerous because the enums could potentially change between API versions. Should transmit as part of the JSON.
5+
** To regenerate this file, nagivate to the top level of the ODrive repository and run:
6+
** python Firmware/interface_generator_stub.py --definitions Firmware/odrive-interface.yaml --template tools/arduino_enums_template.j2 --output Arduino/ODriveArduino/ODriveEnums.h
7+
*/
8+
9+
// ODrive.GpioMode
10+
enum GpioMode {
11+
GPIO_MODE_DIGITAL = 0,
12+
GPIO_MODE_DIGITAL_PULL_UP = 1,
13+
GPIO_MODE_DIGITAL_PULL_DOWN = 2,
14+
GPIO_MODE_ANALOG_IN = 3,
15+
GPIO_MODE_UART_A = 4,
16+
GPIO_MODE_UART_B = 5,
17+
GPIO_MODE_UART_C = 6,
18+
GPIO_MODE_CAN_A = 7,
19+
GPIO_MODE_I2C_A = 8,
20+
GPIO_MODE_SPI_A = 9,
21+
GPIO_MODE_PWM = 10,
22+
GPIO_MODE_ENC0 = 11,
23+
GPIO_MODE_ENC1 = 12,
24+
GPIO_MODE_ENC2 = 13,
25+
GPIO_MODE_MECH_BRAKE = 14,
26+
GPIO_MODE_STATUS = 15,
27+
};
28+
29+
// ODrive.StreamProtocolType
30+
enum StreamProtocolType {
31+
STREAM_PROTOCOL_TYPE_FIBRE = 0,
32+
STREAM_PROTOCOL_TYPE_ASCII = 1,
33+
STREAM_PROTOCOL_TYPE_STDOUT = 2,
34+
STREAM_PROTOCOL_TYPE_ASCII_AND_STDOUT = 3,
35+
};
36+
37+
// ODrive.Can.Protocol
38+
enum Protocol {
39+
PROTOCOL_SIMPLE = 0x00000001,
40+
};
41+
42+
// ODrive.Axis.AxisState
43+
enum AxisState {
44+
AXIS_STATE_UNDEFINED = 0,
45+
AXIS_STATE_IDLE = 1,
46+
AXIS_STATE_STARTUP_SEQUENCE = 2,
47+
AXIS_STATE_FULL_CALIBRATION_SEQUENCE = 3,
48+
AXIS_STATE_MOTOR_CALIBRATION = 4,
49+
AXIS_STATE_ENCODER_INDEX_SEARCH = 6,
50+
AXIS_STATE_ENCODER_OFFSET_CALIBRATION = 7,
51+
AXIS_STATE_CLOSED_LOOP_CONTROL = 8,
52+
AXIS_STATE_LOCKIN_SPIN = 9,
53+
AXIS_STATE_ENCODER_DIR_FIND = 10,
54+
AXIS_STATE_HOMING = 11,
55+
AXIS_STATE_ENCODER_HALL_POLARITY_CALIBRATION = 12,
56+
AXIS_STATE_ENCODER_HALL_PHASE_CALIBRATION = 13,
57+
};
58+
59+
// ODrive.Encoder.Mode
60+
enum EncoderMode {
61+
ENCODER_MODE_INCREMENTAL = 0,
62+
ENCODER_MODE_HALL = 1,
63+
ENCODER_MODE_SINCOS = 2,
64+
ENCODER_MODE_SPI_ABS_CUI = 256,
65+
ENCODER_MODE_SPI_ABS_AMS = 257,
66+
ENCODER_MODE_SPI_ABS_AEAT = 258,
67+
ENCODER_MODE_SPI_ABS_RLS = 259,
68+
ENCODER_MODE_SPI_ABS_MA732 = 260,
69+
};
70+
71+
// ODrive.Controller.ControlMode
72+
enum ControlMode {
73+
CONTROL_MODE_VOLTAGE_CONTROL = 0,
74+
CONTROL_MODE_TORQUE_CONTROL = 1,
75+
CONTROL_MODE_VELOCITY_CONTROL = 2,
76+
CONTROL_MODE_POSITION_CONTROL = 3,
77+
};
78+
79+
// ODrive.Controller.InputMode
80+
enum InputMode {
81+
INPUT_MODE_INACTIVE = 0,
82+
INPUT_MODE_PASSTHROUGH = 1,
83+
INPUT_MODE_VEL_RAMP = 2,
84+
INPUT_MODE_POS_FILTER = 3,
85+
INPUT_MODE_MIX_CHANNELS = 4,
86+
INPUT_MODE_TRAP_TRAJ = 5,
87+
INPUT_MODE_TORQUE_RAMP = 6,
88+
INPUT_MODE_MIRROR = 7,
89+
INPUT_MODE_TUNING = 8,
90+
};
91+
92+
// ODrive.Motor.MotorType
93+
enum MotorType {
94+
MOTOR_TYPE_HIGH_CURRENT = 0,
95+
MOTOR_TYPE_GIMBAL = 2,
96+
MOTOR_TYPE_ACIM = 3,
97+
};
98+
99+
// ODrive.Error
100+
enum ODriveError {
101+
ODRIVE_ERROR_NONE = 0x00000000,
102+
ODRIVE_ERROR_CONTROL_ITERATION_MISSED = 0x00000001,
103+
ODRIVE_ERROR_DC_BUS_UNDER_VOLTAGE = 0x00000002,
104+
ODRIVE_ERROR_DC_BUS_OVER_VOLTAGE = 0x00000004,
105+
ODRIVE_ERROR_DC_BUS_OVER_REGEN_CURRENT = 0x00000008,
106+
ODRIVE_ERROR_DC_BUS_OVER_CURRENT = 0x00000010,
107+
ODRIVE_ERROR_BRAKE_DEADTIME_VIOLATION = 0x00000020,
108+
ODRIVE_ERROR_BRAKE_DUTY_CYCLE_NAN = 0x00000040,
109+
ODRIVE_ERROR_INVALID_BRAKE_RESISTANCE = 0x00000080,
110+
};
111+
112+
// ODrive.Can.Error
113+
enum CanError {
114+
CAN_ERROR_NONE = 0x00000000,
115+
CAN_ERROR_DUPLICATE_CAN_IDS = 0x00000001,
116+
};
117+
118+
// ODrive.Axis.Error
119+
enum AxisError {
120+
AXIS_ERROR_NONE = 0x00000000,
121+
AXIS_ERROR_INVALID_STATE = 0x00000001,
122+
AXIS_ERROR_MOTOR_FAILED = 0x00000040,
123+
AXIS_ERROR_SENSORLESS_ESTIMATOR_FAILED = 0x00000080,
124+
AXIS_ERROR_ENCODER_FAILED = 0x00000100,
125+
AXIS_ERROR_CONTROLLER_FAILED = 0x00000200,
126+
AXIS_ERROR_WATCHDOG_TIMER_EXPIRED = 0x00000800,
127+
AXIS_ERROR_MIN_ENDSTOP_PRESSED = 0x00001000,
128+
AXIS_ERROR_MAX_ENDSTOP_PRESSED = 0x00002000,
129+
AXIS_ERROR_ESTOP_REQUESTED = 0x00004000,
130+
AXIS_ERROR_HOMING_WITHOUT_ENDSTOP = 0x00020000,
131+
AXIS_ERROR_OVER_TEMP = 0x00040000,
132+
AXIS_ERROR_UNKNOWN_POSITION = 0x00080000,
133+
};
134+
135+
// ODrive.Motor.Error
136+
enum MotorError {
137+
MOTOR_ERROR_NONE = 0x00000000,
138+
MOTOR_ERROR_PHASE_RESISTANCE_OUT_OF_RANGE = 0x00000001,
139+
MOTOR_ERROR_PHASE_INDUCTANCE_OUT_OF_RANGE = 0x00000002,
140+
MOTOR_ERROR_DRV_FAULT = 0x00000008,
141+
MOTOR_ERROR_CONTROL_DEADLINE_MISSED = 0x00000010,
142+
MOTOR_ERROR_MODULATION_MAGNITUDE = 0x00000080,
143+
MOTOR_ERROR_CURRENT_SENSE_SATURATION = 0x00000400,
144+
MOTOR_ERROR_CURRENT_LIMIT_VIOLATION = 0x00001000,
145+
MOTOR_ERROR_MODULATION_IS_NAN = 0x00010000,
146+
MOTOR_ERROR_MOTOR_THERMISTOR_OVER_TEMP = 0x00020000,
147+
MOTOR_ERROR_FET_THERMISTOR_OVER_TEMP = 0x00040000,
148+
MOTOR_ERROR_TIMER_UPDATE_MISSED = 0x00080000,
149+
MOTOR_ERROR_CURRENT_MEASUREMENT_UNAVAILABLE = 0x00100000,
150+
MOTOR_ERROR_CONTROLLER_FAILED = 0x00200000,
151+
MOTOR_ERROR_I_BUS_OUT_OF_RANGE = 0x00400000,
152+
MOTOR_ERROR_BRAKE_RESISTOR_DISARMED = 0x00800000,
153+
MOTOR_ERROR_SYSTEM_LEVEL = 0x01000000,
154+
MOTOR_ERROR_BAD_TIMING = 0x02000000,
155+
MOTOR_ERROR_UNKNOWN_PHASE_ESTIMATE = 0x04000000,
156+
MOTOR_ERROR_UNKNOWN_PHASE_VEL = 0x08000000,
157+
MOTOR_ERROR_UNKNOWN_TORQUE = 0x10000000,
158+
MOTOR_ERROR_UNKNOWN_CURRENT_COMMAND = 0x20000000,
159+
MOTOR_ERROR_UNKNOWN_CURRENT_MEASUREMENT = 0x40000000,
160+
MOTOR_ERROR_UNKNOWN_VBUS_VOLTAGE = 0x80000000,
161+
MOTOR_ERROR_UNKNOWN_VOLTAGE_COMMAND = 0x100000000,
162+
MOTOR_ERROR_UNKNOWN_GAINS = 0x200000000,
163+
MOTOR_ERROR_CONTROLLER_INITIALIZING = 0x400000000,
164+
MOTOR_ERROR_UNBALANCED_PHASES = 0x800000000,
165+
};
166+
167+
// ODrive.Controller.Error
168+
enum ControllerError {
169+
CONTROLLER_ERROR_NONE = 0x00000000,
170+
CONTROLLER_ERROR_OVERSPEED = 0x00000001,
171+
CONTROLLER_ERROR_INVALID_INPUT_MODE = 0x00000002,
172+
CONTROLLER_ERROR_UNSTABLE_GAIN = 0x00000004,
173+
CONTROLLER_ERROR_INVALID_MIRROR_AXIS = 0x00000008,
174+
CONTROLLER_ERROR_INVALID_LOAD_ENCODER = 0x00000010,
175+
CONTROLLER_ERROR_INVALID_ESTIMATE = 0x00000020,
176+
CONTROLLER_ERROR_INVALID_CIRCULAR_RANGE = 0x00000040,
177+
CONTROLLER_ERROR_SPINOUT_DETECTED = 0x00000080,
178+
};
179+
180+
// ODrive.Encoder.Error
181+
enum EncoderError {
182+
ENCODER_ERROR_NONE = 0x00000000,
183+
ENCODER_ERROR_UNSTABLE_GAIN = 0x00000001,
184+
ENCODER_ERROR_CPR_POLEPAIRS_MISMATCH = 0x00000002,
185+
ENCODER_ERROR_NO_RESPONSE = 0x00000004,
186+
ENCODER_ERROR_UNSUPPORTED_ENCODER_MODE = 0x00000008,
187+
ENCODER_ERROR_ILLEGAL_HALL_STATE = 0x00000010,
188+
ENCODER_ERROR_INDEX_NOT_FOUND_YET = 0x00000020,
189+
ENCODER_ERROR_ABS_SPI_TIMEOUT = 0x00000040,
190+
ENCODER_ERROR_ABS_SPI_COM_FAIL = 0x00000080,
191+
ENCODER_ERROR_ABS_SPI_NOT_READY = 0x00000100,
192+
ENCODER_ERROR_HALL_NOT_CALIBRATED_YET = 0x00000200,
193+
};
194+
195+
// ODrive.SensorlessEstimator.Error
196+
enum SensorlessEstimatorError {
197+
SENSORLESS_ESTIMATOR_ERROR_NONE = 0x00000000,
198+
SENSORLESS_ESTIMATOR_ERROR_UNSTABLE_GAIN = 0x00000001,
199+
SENSORLESS_ESTIMATOR_ERROR_UNKNOWN_CURRENT_MEASUREMENT = 0x00000002,
200+
};
201+
202+
#endif

‎huron_driver/can/can_helpers.h

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#pragma once
2+
3+
#include <stdint.h>
4+
#include <algorithm>
5+
#include <cstring>
6+
#include <iterator>
7+
8+
struct can_Message_t {
9+
uint32_t id = 0x000; // 11-bit max is 0x7ff, 29-bit max is 0x1FFFFFFF
10+
bool isExt = false;
11+
bool rtr = false;
12+
uint8_t len = 8;
13+
uint8_t buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
14+
} ;
15+
16+
struct can_Signal_t {
17+
const uint8_t startBit;
18+
const uint8_t length;
19+
const bool isIntel;
20+
const float factor;
21+
const float offset;
22+
};
23+
24+
struct can_Cyclic_t {
25+
uint32_t cycleTime_ms;
26+
uint32_t lastTime_ms;
27+
};
28+
29+
#include <iterator>
30+
template <typename T>
31+
constexpr T can_getSignal(can_Message_t msg, const uint8_t startBit, const uint8_t length, const bool isIntel) {
32+
uint64_t tempVal = 0;
33+
uint64_t mask = length < 64 ? (1ULL << length) - 1ULL : -1ULL;
34+
35+
if (isIntel) {
36+
std::memcpy(&tempVal, msg.buf, sizeof(tempVal));
37+
tempVal = (tempVal >> startBit) & mask;
38+
} else {
39+
std::reverse(std::begin(msg.buf), std::end(msg.buf));
40+
std::memcpy(&tempVal, msg.buf, sizeof(tempVal));
41+
tempVal = (tempVal >> (64 - startBit - length)) & mask;
42+
}
43+
44+
T retVal;
45+
std::memcpy(&retVal, &tempVal, sizeof(T));
46+
return retVal;
47+
}
48+
49+
template <typename T>
50+
constexpr void can_setSignal(can_Message_t& msg, const T& val, const uint8_t startBit, const uint8_t length, const bool isIntel) {
51+
uint64_t valAsBits = 0;
52+
std::memcpy(&valAsBits, &val, sizeof(val));
53+
54+
uint64_t mask = length < 64 ? (1ULL << length) - 1ULL : -1ULL;
55+
56+
if (isIntel) {
57+
uint64_t data = 0;
58+
std::memcpy(&data, msg.buf, sizeof(data));
59+
60+
data &= ~(mask << startBit);
61+
data |= valAsBits << startBit;
62+
63+
std::memcpy(msg.buf, &data, sizeof(data));
64+
} else {
65+
uint64_t data = 0;
66+
std::reverse(std::begin(msg.buf), std::end(msg.buf));
67+
std::memcpy(&data, msg.buf, sizeof(data));
68+
69+
data &= ~(mask << (64 - startBit - length));
70+
data |= valAsBits << (64 - startBit - length);
71+
72+
std::memcpy(msg.buf, &data, sizeof(data));
73+
std::reverse(std::begin(msg.buf), std::end(msg.buf));
74+
}
75+
}
76+
77+
template<typename T>
78+
void can_setSignal(can_Message_t& msg, const T& val, const uint8_t startBit, const uint8_t length, const bool isIntel, const float factor, const float offset) {
79+
T scaledVal = static_cast<T>((val - offset) / factor);
80+
can_setSignal<T>(msg, scaledVal, startBit, length, isIntel);
81+
}
82+
83+
template<typename T>
84+
float can_getSignal(can_Message_t msg, const uint8_t startBit, const uint8_t length, const bool isIntel, const float factor, const float offset) {
85+
T retVal = can_getSignal<T>(msg, startBit, length, isIntel);
86+
return (retVal * factor) + offset;
87+
}
88+
89+
template <typename T>
90+
float can_getSignal(can_Message_t msg, const can_Signal_t& signal) {
91+
return can_getSignal<T>(msg, signal.startBit, signal.length, signal.isIntel, signal.factor, signal.offset);
92+
}
93+
94+
template <typename T>
95+
void can_setSignal(can_Message_t& msg, const T& val, const can_Signal_t& signal) {
96+
can_setSignal(msg, val, signal.startBit, signal.length, signal.isIntel, signal.factor, signal.offset);
97+
}

0 commit comments

Comments
 (0)
Please sign in to comment.