One Motor 0.6.0
RoboMaster全平台一站式电机驱动库
载入中...
搜索中...
未找到
DjiMotor.hpp
1#ifndef ONEMOTOR_DJIMOTOR_HPP
2#define ONEMOTOR_DJIMOTOR_HPP
3#include <concepts>
4
5#include "DjiMotorFrames.hpp"
6#include "MotorManager.hpp"
7#include "Traits.hpp"
9#include <OneMotor/Control/PIDChain.hpp>
12
13
14namespace OneMotor::Motor::DJI
15{
16 using PIDFeatures = Control::FeaturePack<
17 Control::WithDeadband,
18 Control::WithIntegralLimit,
19 Control::WithOutputLimit,
20 Control::WithOutputFilter,
21 Control::WithDerivativeFilter
22 >;
23
24 template <typename Traits, uint8_t id>
25 concept ValidMotorId = requires
26 {
27 { Traits::max_id } -> std::convertible_to<uint8_t>;
28 } && (id >= 1 && id <= Traits::max_id);
29
30 template <typename Traits, uint8_t id, typename... PID_Nodes>
32 class DjiMotor
33 {
34 public:
35 explicit DjiMotor(Can::CanDriver& driver, const Control::PIDChain<PID_Nodes...>& pid_chain) :
36 m_driver(driver),
37 m_pid_chain(pid_chain)
38 {
39 (void)m_driver.open()
40 .or_else([](const auto& e) { panic(std::move(e.message)); });
42 (void)manager.registerMotor(m_driver, Traits::template feedback_id<id>()).or_else([](const auto& e)
43 {
44 panic(std::move(e.message));
45 });
46 manager
47 .pushOutput(m_driver, Traits::template control_id<id>(), Traits::template control_offset<id>(), 0, 0);
48
49 (void)driver.registerCallback({Traits::template feedback_id<id>()}, [this](Can::CanFrame&& frame)
50 {
51 this->m_disabled_func(std::move(frame));
52 }).or_else([](const auto& e)
53 {
54 panic(std::move(e.message));
55 });
56 };
57
58 ~DjiMotor()
59 {
61 (void)manager.deregisterMotor(m_driver, Traits::template control_id<id>()).or_else([](const auto& e)
62 {
63 panic(std::move(e.message));
64 });
65 };
66
67 tl::expected<void, Error> enable()
68 {
69 return m_driver.registerCallback({Traits::template feedback_id<id>()}, [this](Can::CanFrame&& frame)
70 {
71 this->m_enabled_func(std::move(frame));
72 });
73 }
74
75 tl::expected<void, Error> disable()
76 {
77 return m_driver.registerCallback({Traits::template feedback_id<id>()}, [this](Can::CanFrame&& frame)
78 {
79 this->m_disabled_func(std::move(frame));
80 });
81 }
82
83 void setAngRef(const float ref)
84 {
85 m_ang_ref.store(ref, std::memory_order_release);
86 }
87
88 void setPosRef(const float ref)
89 {
90 m_pos_ref.store(ref, std::memory_order_release);
91 }
92
93 MotorStatus getStatus()
94 {
95 return m_Buffer.readCopy();
96 }
97
98 private:
99 static constexpr float RPM_2_ANGLE_PER_SEC = 6.0f;
100
101 static void trMsgToStatus(const RawStatusFrame& frame,
102 MotorStatus& status)
103 {
104 auto& [last_ecd, ecd, angle_single_round, angular, real_current, temperature, total_angle, total_round,
105 output_current] = status;
106
107 ecd = frame.ecd;
108 real_current = frame.current;
109 temperature = frame.temperature;
110 angle_single_round = Traits::ecd_to_angle(static_cast<float>(ecd));
111 angular = RPM_2_ANGLE_PER_SEC * static_cast<float>(frame.rpm);
112
113 if (ecd - last_ecd > 4096)
114 {
115 total_round--;
116 }
117 else if (ecd - last_ecd < -4096)
118 {
119 total_round++;
120 }
121 total_angle = static_cast<float>(total_round) * 360 + angle_single_round;
122 last_ecd = ecd;
123 }
124
125 void m_disabled_func(Can::CanFrame&& frame)
126 {
127 const auto msg = static_cast<RawStatusFrame>(frame);
128 trMsgToStatus(msg, this->m_Buffer.write());
129 this->m_Buffer.swap();
130 }
131
132 void m_enabled_func(Can::CanFrame&& frame)
133 {
134#ifdef CONFIG_OM_DJI_MOTOR_SKIP_N_FRAME
135#if CONFIG_OM_DJI_MOTOR_SKIP_N_FRAME != 0
136 if (m_skip_frame++ < CONFIG_OM_DJI_MOTOR_SKIP_N_FRAME) return;
137 m_skip_frame = 0;
138#endif
139#endif
140 const auto msg = static_cast<RawStatusFrame>(frame);
141 trMsgToStatus(msg, this->m_Buffer.write());
142 float ang_result{};
143 if constexpr (Control::PIDChain<PID_Nodes...>::Size == 1)
144 {
145 ang_result = m_pid_chain.compute(m_ang_ref.load(std::memory_order_acquire),
146 this->m_Buffer.write().angular);
147 }
148 else if constexpr (Control::PIDChain<PID_Nodes...>::Size == 2)
149 {
150 ang_result = m_pid_chain
151 .compute(
152 m_pos_ref.load(std::memory_order_acquire), this->m_Buffer.write().total_angle,
153 this->m_Buffer.write().angular
154 );
155 }
156 ang_result = std::clamp(ang_result, static_cast<float>(-Traits::max_current),
157 static_cast<float>(Traits::max_current));
158 const auto output_current = static_cast<int16_t>(ang_result);
159 this->m_Buffer.write().output_current = output_current;
160 this->m_Buffer.swap();
161 const uint8_t hi_byte = output_current >> 8;
162 const uint8_t lo_byte = output_current & 0xFF;
163 MotorManager::getInstance().pushOutput(m_driver, Traits::template control_id<id>(),
164 Traits::template control_offset<id>(),
165 lo_byte,
166 hi_byte);
167 }
168
169 Can::CanDriver& m_driver;
171 Control::PIDChain<PID_Nodes...> m_pid_chain;
172
173 std::atomic<float> m_ang_ref{};
174 std::atomic<float> m_pos_ref{};
175#ifdef CONFIG_OM_DJI_MOTOR_SKIP_N_FRAME
176#if CONFIG_OM_DJI_MOTOR_SKIP_N_FRAME != 0
177 uint8_t m_skip_frame{};
178#endif
179#endif
180 };
181
182 template <typename Traits, uint8_t id, typename... PID_Nodes>
183 DjiMotor<Traits, id, PID_Nodes...> createDjiMotor(Can::CanDriver& driver,
184 const Control::PIDChain<PID_Nodes...>& pid_chain)
185 {
186 return DjiMotor<Traits, id, PID_Nodes...>(driver, pid_chain);
187 }
188}
189
190#endif //ONEMOTOR_DJIMOTOR_HPP
提供一个统一的CAN总线驱动接口。
定义 DoubleBuffer 类,用于在多线程模型下保证电机状态信息的安全更新
定义了DJI电机管理器,用于统一发送电机控制指令。
提供一个用于处理严重错误的全局函数。
void panic(const std::string &&message)
触发一个严重错误(panic)。
定义 L_Panic.cpp:7
CAN总线驱动类,封装了底层CAN接口的打开、关闭、发送和接收回调注册等操作。
定义 CanDriver.hpp:35
tl::expected< void, Error > registerCallback(const std::set< size_t > &can_ids, const CallbackFunc &func)
注册一个回调函数,用于处理特定CAN ID的数据帧。
定义 L_CanDriver.cpp:51
PID处理链。
定义 PIDChain.hpp:15
定义 DoubleBuffer.hpp:22
定义 DjiMotor.hpp:33
DJI电机管理器单例类。
定义 MotorManager.hpp:36
tl::expected< void, Error > deregisterMotor(Can::CanDriver &driver, uint16_t canId) noexcept
从管理器中注销一个电机。
定义 N_MotorManager.cpp:75
void pushOutput(Can::CanDriver &driver, uint16_t control_can_id, uint8_t offset, uint8_t lo_value, uint8_t hi_value) noexcept
将一个电机的目标电流值推送到发送缓冲区。
定义 N_MotorManager.cpp:93
static MotorManager & getInstance()
获取MotorManager的单例实例。
定义 N_MotorManager.cpp:34
tl::expected< void, Error > registerMotor(Can::CanDriver &driver, uint16_t canId) noexcept
向管理器注册一个电机。
定义 N_MotorManager.cpp:40
一个与平台无关的CAN帧结构体。
定义 CanFrame.hpp:36
定义 DjiMotorFrames.hpp:83
DJI电机原始状态反馈的CAN帧的直接映射。
定义 DjiMotorFrames.hpp:25
uint16_t ecd
编码器原始值 (0~8191)
定义 DjiMotorFrames.hpp:76
int16_t current
电机实际电流 (mA)
定义 DjiMotorFrames.hpp:78
uint8_t temperature
电机温度 (°C)
定义 DjiMotorFrames.hpp:79
int16_t rpm
转速 (RPM)
定义 DjiMotorFrames.hpp:77