Haptic Controller
Loading...
Searching...
No Matches
comm_controller.hpp
Go to the documentation of this file.
1#pragma once
2#include <Arduino.h>
3#include "ODriveCAN.h"
4#include <FlexCAN_T4.h>
5#include "ODriveFlexCAN.hpp"
6#include "teensy_can.h"
7#include "defines.h"
10
19
23template <CAN_DEV_TABLE ODRIVE_CAN0, CAN_DEV_TABLE ODRIVE_CAN1>
25{
26public:
27 CommsController() = default;
28
38 VirtualTimerGroup &timer_group,
39 FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_256> &odrive_can0,
40 FlexCAN_T4<CAN3, RX_SIZE_256, TX_SIZE_256> &odrive_can1,
43 _MB_ptr F,
44 ICAN &teensy_can)
51 {
52 // Init Odrive CAN
53 odrive_can0_.begin();
54 odrive_can0_.setBaudRate(CAN_BAUDRATE);
55 odrive_can0_.setMaxMB(16);
56 odrive_can0_.enableFIFO();
57 odrive_can0_.enableFIFOInterrupt();
58 odrive_can0_.onReceive(F);
59
60 odrive_can1_.begin();
61 odrive_can1_.setBaudRate(CAN_BAUDRATE);
62 odrive_can1_.setMaxMB(16);
63 odrive_can1_.enableFIFO();
64 odrive_can1_.enableFIFOInterrupt();
65 odrive_can1_.onReceive(F);
66
67 // Todo: move TeensyCAN inside here and see if that works
68 }
69
71 VirtualTimerGroup &timer_group;
72
74 FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_256> &odrive_can0_;
75
77 FlexCAN_T4<CAN3, RX_SIZE_256, TX_SIZE_256> &odrive_can1_;
78
81
84
86
89
90 MakeSignedCANSignal(float, 0, 32, 0.0001, 0) end_eff_pos_0_tx{};
91 MakeSignedCANSignal(float, 32, 32, 0.0001, 0) end_eff_pos_1_tx{};
93 CANTXMessage<2> tx_end_eff_pos_message{teensy_can, END_EFFECTOR_POS_TX_ID, 8, 500, timer_group,
94 end_eff_pos_0_tx, end_eff_pos_1_tx};
95
96 MakeSignedCANSignal(float, 0, 32, 0.0001, 0) end_eff_pos_0_rx{};
97 MakeSignedCANSignal(float, 32, 32, 0.0001, 0) end_eff_pos_1_rx{};
99 CANRXMessage<2> rx_end_eff_pos_message{teensy_can, END_EFFECTOR_POS_RX_ID, end_eff_pos_0_rx, end_eff_pos_1_rx};
100
101 MakeSignedCANSignal(float, 0, 32, 0.0001, 0) end_eff_vel_0_tx{};
102 MakeSignedCANSignal(float, 32, 32, 0.0001, 0) end_eff_vel_1_tx{};
104 CANTXMessage<2> tx_end_eff_vel_message{teensy_can, END_EFFECTOR_VEL_TX_ID, 8, 500, timer_group, end_eff_vel_0_tx,
105 end_eff_vel_1_tx};
106
107 MakeSignedCANSignal(float, 0, 32, 0.0001, 0) end_eff_vel_0_rx{};
108 MakeSignedCANSignal(float, 32, 32, 0.0001, 0) end_eff_vel_1_rx{};
110 CANRXMessage<2> rx_end_eff_vel_message{teensy_can, END_EFFECTOR_VEL_RX_ID, end_eff_vel_0_rx, end_eff_vel_1_rx};
111
112 MakeUnsignedCANSignal(ControllerState, 0, 4, 1, 0) system_state_tx{};
113 MakeUnsignedCANSignal(bool, 4, 1, 1, 0) odrive0_heartbeat_active_tx{};
114 MakeUnsignedCANSignal(bool, 5, 1, 1, 0) encoder0_active_tx{};
115 MakeUnsignedCANSignal(bool, 6, 1, 1, 0) motor0_active_tx{};
116 MakeUnsignedCANSignal(bool, 7, 1, 1, 0) odrive1_heartbeat_active_tx{};
117 MakeUnsignedCANSignal(bool, 8, 1, 1, 0) encoder1_active_tx{};
118 MakeUnsignedCANSignal(bool, 9, 1, 1, 0) motor1_active_tx{};
119 MakeUnsignedCANSignal(bool, 10, 1, 1, 0) mirror_system_active_tx{};
121 CANTXMessage<8> tx_heartbeat_message{teensy_can, HEARTBEAT_TX_ID, 1, 10000, timer_group,
122 odrive0_heartbeat_active_tx,
123 encoder0_active_tx, motor0_active_tx, odrive1_heartbeat_active_tx,
124 encoder1_active_tx, motor1_active_tx, mirror_system_active_tx, system_state_tx};
125
126 MakeUnsignedCANSignal(ControllerState, 0, 4, 1, 0) system_state_rx{};
127 MakeUnsignedCANSignal(bool, 4, 1, 1, 0) odrive0_heartbeat_active_rx{};
128 MakeUnsignedCANSignal(bool, 5, 1, 1, 0) encoder0_active_rx{};
129 MakeUnsignedCANSignal(bool, 6, 1, 1, 0) motor0_active_rx{};
130 MakeUnsignedCANSignal(bool, 7, 1, 1, 0) odrive1_heartbeat_active_rx{};
131 MakeUnsignedCANSignal(bool, 8, 1, 1, 0) encoder1_active_rx{};
132 MakeUnsignedCANSignal(bool, 9, 1, 1, 0) motor1_active_rx{};
133 MakeUnsignedCANSignal(bool, 10, 1, 1, 0) mirror_system_active_rx{};
135 CANRXMessage<8> rx_heartbeat_message{teensy_can, HEARTBEAT_RX_ID, [this]()
136 { handleHeartbeat(); },
137 odrive0_heartbeat_active_rx, encoder0_active_rx, motor0_active_rx, odrive1_heartbeat_active_rx,
138 encoder1_active_rx, motor1_active_rx, mirror_system_active_rx, system_state_rx};
139
144 {
147
150
153
154 teensy_can.RegisterRXMessage(rx_end_eff_pos_message);
155 teensy_can.RegisterRXMessage(rx_end_eff_vel_message);
156 teensy_can.RegisterRXMessage(rx_heartbeat_message);
157
158 // Uncomment these for unmapped ODrives
159 // odrv1_.enable_anticogging();
160 // odrv0_.enable_anticogging();
161
162 return true;
163 }
164
166 void Tick()
167 {
168 // Serial.println("Comms Controller Tick");
169 // Serial.println(system_state_rx);
170
171 pumpEvents(odrive_can0_);
172 pumpEvents(odrive_can1_);
175 ODRIVE_HEARTBEAT_TIMEOUT;
178 ODRIVE_HEARTBEAT_TIMEOUT;
179 teensy_heartbeat_timeout = millis() - last_received_time > TEENSY_HEARTBEAT_TIMEOUT;
180 }
181
185 template <typename T>
186 void find_odrive(T odrv_ctrl)
187 {
188 Serial.println("Waiting for ODrive" + String(odrv_ctrl.odrv_user_data_.node_id) + "...");
189 while (!odrv_ctrl.odrv_user_data_.received_heartbeat)
190 {
191 Tick();
192 delay(100);
193 Serial.println("Waiting for ODrive" + String(odrv_ctrl.odrv_user_data_.node_id) + "...");
194 // Serial.print("Recv hb cc: ");
195 // Serial.println(odrv_ctrl.odrv_user_data_.received_heartbeat);
196 }
197 Serial.println("Found ODrive");
198 }
199
203 template <typename T>
204 void startup_odrive(T odrv_ctrl)
205 {
206 Serial.println("Enabling closed loop control...");
207 while (odrv_ctrl.odrv_user_data_.last_heartbeat.Axis_State !=
208 ODriveAxisState::AXIS_STATE_CLOSED_LOOP_CONTROL)
209 {
210 // odrv_ctrl.odrv_.clearErrors();
211 delay(1);
212 odrv_ctrl.odrv_.setState(ODriveAxisState::AXIS_STATE_CLOSED_LOOP_CONTROL);
213 for (int i = 0; i < 15; ++i)
214 {
215 delay(10);
217 }
218 }
219 Serial.println("ODrive running!");
220 }
221
225 {
226 return odrv0_.odrv_user_data_;
227 }
228
232 {
233 return odrv1_.odrv_user_data_;
234 }
235
238 inline ODriveCAN &get_odrv0()
239 {
240 return odrv0_.odrv_;
241 }
242
245 inline ODriveCAN &get_odrv1()
246 {
247 return odrv1_.odrv_;
248 }
249
258
259private:
260 uint32_t last_received_time;
261
263 void handleHeartbeat()
264 {
265 last_received_time = millis();
266 }
267};
Comms Controller class for managing Canlines.
MakeSignedCANSignal(float, 0, 32, 0.0001, 0) end_eff_vel_0_rx
OdriveController< CAN3 > & odrv1_
Address of second odrive.
MakeUnsignedCANSignal(bool, 4, 1, 1, 0) odrive0_heartbeat_active_tx
MakeUnsignedCANSignal(bool, 9, 1, 1, 0) motor1_active_rx
ODriveUserData & get_odrv1_data()
Get the odrv1 user data.
MakeUnsignedCANSignal(bool, 5, 1, 1, 0) encoder0_active_rx
FlexCAN_T4< CAN3, RX_SIZE_256, TX_SIZE_256 > & odrive_can1_
Canline for second odrive.
ODriveCAN & get_odrv0()
Get odrv0.
bool comms_timeout()
Communication timeout on either Teensy or ODrives.
CommsController()=default
MakeSignedCANSignal(float, 32, 32, 0.0001, 0) end_eff_vel_1_rx
MakeUnsignedCANSignal(bool, 8, 1, 1, 0) encoder1_active_rx
MakeUnsignedCANSignal(bool, 5, 1, 1, 0) encoder0_active_tx
MakeUnsignedCANSignal(bool, 10, 1, 1, 0) mirror_system_active_tx
MakeUnsignedCANSignal(ControllerState, 0, 4, 1, 0) system_state_tx
CANTXMessage< 2 > tx_end_eff_vel_message
End effectors velocities to send to the mirror Teensy.
MakeSignedCANSignal(float, 32, 32, 0.0001, 0) end_eff_pos_1_rx
CANTXMessage< 8 > tx_heartbeat_message
Values to send to the ODrive.
CommsController(VirtualTimerGroup &timer_group, FlexCAN_T4< CAN2, RX_SIZE_256, TX_SIZE_256 > &odrive_can0, FlexCAN_T4< CAN3, RX_SIZE_256, TX_SIZE_256 > &odrive_can1, OdriveController< CAN2 > &odrv0, OdriveController< CAN3 > &odrv1, _MB_ptr F, ICAN &teensy_can)
Construct the comms controller.
FlexCAN_T4< CAN2, RX_SIZE_256, TX_SIZE_256 > & odrive_can0_
Canline for first odrive.
ODriveCAN & get_odrv1()
Get odrv1.
MakeSignedCANSignal(float, 32, 32, 0.0001, 0) end_eff_pos_1_tx
MakeUnsignedCANSignal(bool, 6, 1, 1, 0) motor0_active_tx
ODriveUserData & get_odrv0_data()
Get the odrv0 user data.
MakeUnsignedCANSignal(bool, 4, 1, 1, 0) odrive0_heartbeat_active_rx
CANTXMessage< 2 > tx_end_eff_pos_message
End effectors positions to send to the mirror Teensy.
MakeUnsignedCANSignal(ControllerState, 0, 4, 1, 0) system_state_rx
void startup_odrive(T odrv_ctrl)
Enable closed loop control on odrive.
bool Initialize()
Initialize the ODrives and the Teensy CAN, must be called in setup procedure.
MakeUnsignedCANSignal(bool, 9, 1, 1, 0) motor1_active_tx
MakeUnsignedCANSignal(bool, 8, 1, 1, 0) encoder1_active_tx
MakeSignedCANSignal(float, 0, 32, 0.0001, 0) end_eff_pos_0_tx
void find_odrive(T odrv_ctrl)
Receive hearbeats on odrives.
ICAN & teensy_can
: Teensy Canline
MakeUnsignedCANSignal(bool, 7, 1, 1, 0) odrive1_heartbeat_active_rx
MakeSignedCANSignal(float, 0, 32, 0.0001, 0) end_eff_pos_0_rx
OdriveController< CAN2 > & odrv0_
Address of first odrive.
MakeSignedCANSignal(float, 32, 32, 0.0001, 0) end_eff_vel_1_tx
MakeUnsignedCANSignal(bool, 10, 1, 1, 0) mirror_system_active_rx
MakeSignedCANSignal(float, 0, 32, 0.0001, 0) end_eff_vel_0_tx
CANRXMessage< 2 > rx_end_eff_vel_message
End effectors velocities received by the mirror Teensy.
CANRXMessage< 2 > rx_end_eff_pos_message
End effectors positions received by the mirror Teensy.
CANRXMessage< 8 > rx_heartbeat_message
Values received by the ODrive.
void Tick()
Tick Odrive CAN buses and checks timeouts.
MakeUnsignedCANSignal(bool, 6, 1, 1, 0) motor0_active_rx
VirtualTimerGroup & timer_group
Address of timer group that the comms rely on.
MakeUnsignedCANSignal(bool, 7, 1, 1, 0) odrive1_heartbeat_active_tx
Class that abstracts operations with the ODrive/.
ODriveUserData & odrv_user_data_
struct to store user data in
bool startup_odrive_checks()
Set parameters and set the motor to torque control.
ODriveCAN odrv_
Odrive object to control.
ControllerState
The state of the system.
@ RUNNING
@ ERROR
@ INITIALIZING
@ READY
uint32_t last_received_time
Definition main.cpp:33
OdriveController< CAN3 > odrv1
: Odrive for second joint
Definition main.cpp:46
FlexCAN_T4< CAN2, RX_SIZE_256, TX_SIZE_256 > odrive_can0
Definition main.cpp:36
FlexCAN_T4< CAN3, RX_SIZE_256, TX_SIZE_256 > odrive_can1
Definition main.cpp:37
OdriveController< CAN2 > odrv0
: Odrive for first joint
Definition main.cpp:43
: The Struct to contain feedback from the ODrive
uint32_t last_heartbeat_time