4#include "ODriveFlexCAN.hpp"
6#include "virtualTimer.h"
20#include <Adafruit_NeoPixel.h>
72std::vector<float>
pos = {0.0f, 0.0f};
73std::vector<float>
vel = {0.0f, 0.0f};
128 const auto mirror_pos_0 =
static_cast<float>(
comms_controller.end_eff_pos_0_rx);
129 const auto mirror_pos_2 =
static_cast<float>(
comms_controller.end_eff_pos_1_rx);
131 db_printVal(
pos.at(0));
132 db_printVal(
pos.at(2));
133 db_printVal(
vel.at(0));
134 db_printVal(
vel.at(1));
135 db_printVal(mirror_pos_0);
136 db_printVal(mirror_pos_2);
142 db_printVal(mirror_pos_0);
143 db_printVal(mirror_pos_2);
179 SCB_AIRCR = 0x05FA0004;
188 digitalWrite(RELAY_PIN_OUTPUT, LOW);
197 digitalWrite(RELAY_PIN_OUTPUT, HIGH);
206 Estop_msg_t estop_msg;
215 comms_controller.get_odrv0().setState(ODriveAxisState::AXIS_STATE_CLOSED_LOOP_CONTROL);
217 comms_controller.get_odrv1().setState(ODriveAxisState::AXIS_STATE_CLOSED_LOOP_CONTROL);
241 const auto other_end_eff_x =
static_cast<float>(
comms_controller.end_eff_pos_0_rx);
242 const auto other_end_eff_z =
static_cast<float>(
comms_controller.end_eff_pos_1_rx);
264 digitalWrite(LED_BUILTIN, LOW);
268 digitalWrite(LED_BUILTIN, HIGH);
377 db_println(
"Switching to ERROR");
394 db_println(
"Switching to READY");
413 db_println(
"Switching to RUNNING");
429 db_println(
"Switching to READY");
440 db_println(
"Switching to INITIALIZING");
564 const auto mirror_joint_0 =
static_cast<float>(
comms_controller.end_eff_pos_0_rx);
565 const auto mirror_joint_1 =
static_cast<float>(
comms_controller.end_eff_pos_1_rx);
566 const auto mirror_joint_0_vel =
static_cast<float>(
comms_controller.end_eff_vel_0_rx);
567 const auto mirror_joint_1_vel =
static_cast<float>(
comms_controller.end_eff_vel_1_rx);
569 const auto delta_0 = mirror_joint_0 -
joint_thetas.at(0);
570 const auto delta_1 = mirror_joint_1 -
joint_thetas.at(1);
572 const auto delta_vel_0 = mirror_joint_0_vel -
joint_vels.at(0);
573 const auto delta_vel_1 = mirror_joint_1_vel -
joint_vels.at(1);
575 const float k_0 = 4.0f;
576 const float k_1 = 2.0f;
578 const float c_0 = 0.00f;
579 const float c_1 = 0.00f;
581 const float joint_0_torque = k_0 * delta_0 + c_0 * delta_vel_0;
582 const float joint_1_torque = k_1 * delta_1 + c_1 * delta_vel_1;
586 const auto torques =
tau_to_torque({joint_0_torque + soft_limit.at(0), joint_1_torque + soft_limit.at(1), 0.0});
588 const auto clamped_torque_0 =
limit<float>(torques.at(0), motor_torque_limit);
589 const auto clamped_torque_1 =
limit<float>(torques.at(1), motor_torque_limit);
609 const auto mirror_x =
static_cast<float>(
comms_controller.end_eff_pos_0_rx);
610 const auto mirror_z =
static_cast<float>(
comms_controller.end_eff_pos_1_rx);
611 const auto mirror_x_vel =
static_cast<float>(
comms_controller.end_eff_vel_0_rx);
612 const auto mirror_z_vel =
static_cast<float>(
comms_controller.end_eff_vel_1_rx);
621 const auto delta_x = mirror_x -
pos.at(0);
622 const auto delta_z = mirror_z -
pos.at(2);
624 const auto delta_x_vel = mirror_x_vel -
vel.at(0);
625 const auto delta_z_vel = mirror_z_vel -
vel.at(1);
630 const auto k_x = 500.0f;
631 const auto k_z = 500.0f;
633 const auto c_x = 1.65f;
634 const auto c_z = 1.65f;
636 const auto F_stiffness_x = k_x * delta_x;
637 const auto F_stiffness_z = k_z * delta_z;
639 const auto F_damping_x = c_x * delta_x_vel;
640 const auto F_damping_z = c_z * delta_z_vel;
642 const auto F_kx = F_stiffness_x + F_damping_x;
643 const auto F_kz = F_stiffness_z + F_damping_z;
645 auto tau = J_s.T() * std::vector<float>{F_kx, F_kz};
648 tau.at(0) += soft_limit.at(0);
649 tau.at(1) += soft_limit.at(1);
653 const auto clamped_torque_0 =
limit<float>(torques.at(0), motor_torque_limit);
654 const auto clamped_torque_1 =
limit<float>(torques.at(1), motor_torque_limit);
674 if (digitalRead(DEADMAN_SWITCH) == LOW)
687 Serial.begin(115200);
688 for (
int i = 0; i < 30 && !Serial; ++i)
699 db_println(
"Starting CAN setup");
700 teensy_can.Initialize(ICAN::BaudRate::kBaud1M);
703 db_println(
"CAN failed to initialize: reset required");
708 pinMode(DEADMAN_SWITCH, INPUT);
709 pinMode(RELAY_PIN_OUTPUT, OUTPUT);
713 attachInterrupt(digitalPinToInterrupt(DEADMAN_SWITCH),
checkDeadman, CHANGE);
715 digitalPinToInterrupt(CLEAR_ERROR_BUTTON), []()
724 db_println(
"Switching to INITIALIZING"); },
729 db_println(
"Switching to INITIALIZING");
734 db_println(
"Starting timer setup");
743 db_println(
"Timer complete");
745 db_println(
"Setup complete\n\n");
751 db_endTiming(
"loop");
752 db_startTiming(
"loop");
constexpr float convert_angular_units(float ang, const AngleUnits curr_unit, const AngleUnits desr_unit)
Converts an angle from one unit to another.
Comms Controller class for managing Canlines.
Infinite Impulse Response Filter.
float update(float new_sample)
Class that abstracts operations with the ODrive/.
ODriveCAN odrv_
Odrive object to control.
ControllerState
The state of the system.
std::vector< float > motors_to_joints(std::vector< float > motor_vars)
std::vector< float > phi_to_theta(std::vector< float > motor_phis)
std::vector< float > tau_to_torque(std::vector< float > joint_taus)
std::vector< float > forward_kinematics(std::vector< float > joint_angles)
Performs forward kinematics for the haptic finger.
Matrix spatial_jacobian(std::vector< float > joint_angles)
std::vector< float > soft_limit_torques(std::vector< float > joint_thetas)
bool float_close_compare(float a, float b, float tol=1e-6)
Compare two floats for equality under a tolerance.
T limit(T input, const T max_value, const std::optional< T >(min_value)=std::nullopt)
Clamps an input value to a.
void ledSetup()
Sets the pins for the LEDs as output.
void setColor(int idx, Color color)
Sets the color for the data board LEDs using color struct.
bool isInitialized()
Check if the motors are in the initial position.
void printEverything()
Print statements, set at a separate frequency than others.
void endEffMirrorUpdate()
: Links end effector positions together
ODriveUserData odrv0_user_data
void checkDeadman()
Check the deadman switch state.
void updateSystemInfo()
Update system information struct with new CAN information.
TeensyCAN< 1 > teensy_can
void ledUpdate()
Update the LED strip and on board LED based on the current state, timeouts, and mirror states.
uint32_t last_received_time
void request_enable()
Process enable request, clear errors.
void setup()
setup function before main loop
CommsController< ODRV_CAN0, ODRV_CAN1 > comms_controller
VirtualTimerGroup micro_timer_group
std::vector< float > joint_thetas
OdriveController< CAN3 > odrv1
: Odrive for second joint
void closeRelays()
Close relays to enable motors.
MovingAverageFilter filter_phi_dot_1
bool shouldError()
Check if there is a critical error that should prompt a transition to the error state.
FlexCAN_T4< CAN2, RX_SIZE_256, TX_SIZE_256 > odrive_can0
ControllerState controller_state
FlexCAN_T4< CAN3, RX_SIZE_256, TX_SIZE_256 > odrive_can1
OdriveController< CAN2 > odrv0
: Odrive for first joint
void exitState(ControllerState state)
Process exit state requests.
void enterState(ControllerState state)
Process enter state requests.
void changeState()
Evaluates state transitions based on current state and system information.
void updateAndSendSystemInfo()
Send the end effector position over CAN to the other teensy.
MovingAverageFilter filter_phi_0
VirtualTimerGroup timer_group
std::vector< float > joint_vels
void doReboot()
Reboot the Teensy.
MovingAverageFilter filter_phi_dot_0
MovingAverageFilter filter_phi_1
void request_disable()
Request estop from odrives.
ODriveUserData odrv1_user_data
void jointMirrorUpdate()
: Links joints states
void doState()
Handles the current state of the controller.
void onOdriveCanMessage(const CanMsg &msg)
bool isSynced()
Check if the motors are in sync.
void openRelays()
Open relays to disable motors.
bool clear_safe_errors(ODriveCAN odrv, uint32_t error)
: Clear errors deemed as "Safe to Clean Automatically"
: The Struct to contain feedback from the ODrive
Get_Encoder_Estimates_msg_t last_feedback
Heartbeat_msg_t last_heartbeat
Struct to hold important system information.
SystemInfo(CommsController< ODRV_CAN0, ODRV_CAN1 > &cc)
bool & odrive1_heartbeat_timeout
ControllerState mirror_teensy_state
bool teensy_heartbeat_timeout
bool deadman_switch_pressed
bool & odrive0_heartbeat_timeout
void allUnitTests()
Call in setup() in main.cpp to run unit tests instead of normal operation.