Emakefun Encoder Motor Arduino Lib 1.1.1
Loading...
Searching...
No Matches
encoder_motor.h
Go to the documentation of this file.
1#pragma once
2
3#ifndef _EM_ENCODER_MOTOR_H_
4#define _EM_ENCODER_MOTOR_H_
5
6/**
7 * @file encoder_motor.h
8 */
9
10#include <WString.h>
11
12#include <atomic>
13#include <chrono>
14#include <condition_variable>
15#include <cstdint>
16#include <mutex>
17#include <thread>
18
19#include "esp_arduino_version.h"
20#include "motor.h"
21
22/**
23 * @namespace em
24 */
25namespace em {
26/**
27 * @~Chinese
28 * @class EncoderMotor
29 * @brief 编码电机驱动类
30 * @details 该类主要功能如下:
31 * -# 支持编码器输出信号为A、B两相且A、B两通道信号序列相位差为90度的编码电机。
32 * -# 支持以指定的速度(RPM)驱动电机运转,或者以指定的PWM占空比直接驱动电机。
33 * -# 支持获取电机当前的转速信息,单位为RPM。
34 * -# 支持获取编码脉冲计数值,此计数值在A相下降沿进行更新,电机正转时计数值加1,反转时减1。
35 * -# 支持获取电机驱动器当前设置的PWM占空比。
36 */
37/**
38 * @~English
39 * @class EncoderMotor
40 * @brief Encoder Motor Class
41 * @details The main functions of this class are as follows:
42 * -# Supports encoded motors with encoder output signals of A and B phases and a phase difference of 90 degrees
43 * between the signal sequences of A and B channels.
44 * -# Supports driving the motor at a specified speed (RPM) or directly driving the motor with a specified PWM duty cycle.
45 * -# Supports obtaining the current speed information of the motor in RPM.
46 * -# Supports obtaining the encoder pulse count value. This count value is updated at the falling edge of phase A, incremented
47 * by 1 during forward rotation and decremented by 1 during reverse rotation.
48 * -# Supports obtaining the PWM duty cycle currently set on the motor driver.
49 */
51 public:
52 /**
53 * @~Chinese
54 * @brief 用于明确电机正转时编码器AB相的相位关系,以便在脉冲计数及后续速度计算等操作中依据正确的相位关系进行处理。
55 */
56 /**
57 * @~English
58 * @brief Used to clarify the phase relationship between phase A and phase B of the encoder when the motor is rotating
59 * forward, so that the correct phase relationship can be used in operations such as pulse counting and subsequent speed
60 * calculation.
61 */
62 enum PhaseRelation : uint8_t {
63 /**
64 * @~Chinese
65 * @brief 表示电机正转时A相领先于B相。
66 */
67 /**
68 * @~English
69 * @brief Represents the situation where phase A leads phase B when the motor is rotating forward.
70 */
72
73 /**
74 * @~Chinese
75 * @brief 表示电机正转时B相领先于A相。
76 */
77 /**
78 * @~English
79 * @brief Represents the situation where phase B leads phase A when the motor is rotating forward.
80 */
82 };
83
84 /**
85 * @~Chinese
86 * @brief 构造函数,用于创建一个 EncoderMotor 对象。
87 * @note 该构造函数仅在ESP32 Arduino Core版本大于等于3.0.0时有效,3.0.0以下版本请使用 @ref EncoderMotor(const uint8_t,
88 * const uint8_t, const uint8_t, const uint8_t, const uint8_t, const uint8_t, const uint32_t, const uint32_t, const
89 * PhaseRelation)
90 * @param[in] positive_pin 电机正极引脚编号。
91 * @param[in] negative_pin 电机负极引脚编号。
92 * @param[in] a_pin 编码器A相引脚编号。
93 * @param[in] b_pin 编码器B相引脚编号。
94 * @param[in] ppr 每转脉冲数。
95 * @param[in] reduction_ration 减速比。
96 * @param[in] phase_relation 相位关系(A相领先或B相领先,指电机正转时的情况),参数说明请查阅: @ref PhaseRelation 。
97 * @details
98 * 如果用户不清楚自己所使用的编码电机的phase_relation参数具体取值,可以使用示例程序 @ref detect_phase_relation.ino
99 * 来帮助检测确定该参数的值。
100 */
101 /**
102 * @~English
103 * @brief Constructor for creating an EncoderMotor object.
104 * @note This constructor is only valid when the ESP32 Arduino Core version is greater than or equal to 3.0.0. For versions
105 * below 3.0.0, please use @ref EncoderMotor(const uint8_t, const uint8_t, const uint8_t, const uint8_t, const uint8_t, const
106 * uint8_t, const uint32_t, const uint32_t, const PhaseRelation)
107 * @param[in] positive_pin The pin number of the motor's positive pole.
108 * @param[in] negative_pin The pin number of the motor's negative pole.
109 * @param[in] a_pin The pin number of the encoder's A phase.
110 * @param[in] b_pin The pin number of the encoder's B phase.
111 * @param[in] ppr Pulses per revolution.
112 * @param[in] reduction_ration Reduction ratio.
113 * @param[in] phase_relation Phase relationship (A phase leads or B phase leads, referring to the situation when the motor is
114 * rotating forward), @ref PhaseRelation.
115 * @details
116 * If the user is unsure about the value of the phase_relation parameter for the encoded motor they are using, they
117 * can use the example program @ref detect_phase_relation.ino to help detect and determine the value of this parameter.
118 */
119 EncoderMotor(const uint8_t positive_pin,
120 const uint8_t negative_pin,
121 const uint8_t a_pin,
122 const uint8_t b_pin,
123 const uint32_t ppr,
124 const uint32_t reduction_ration,
125 const PhaseRelation phase_relation);
126 /**
127 * @~Chinese
128 * @brief 构造函数,用于创建一个 EncoderMotor 对象。
129 * @note 此类会使用ESP32的LED Control (LEDC)产生PWM波形驱动电机,在ESP32 Arduino Core版本小于3.0.0时,ESP32 Arduino
130 * Core不会管理LEDC通道,需要用户指定每个引脚对应的LEDC通道,
131 * 所以必须使用该构造函数构造对象,并指定电机正负极引脚对应的LEDC通道,每个pin只能对应一个LEDC通道,请勿重复使用LEDC通道,关于LEDC的说明请查阅官网:
132 * @ref https://docs.espressif.com/projects/arduino-esp32/en/latest/api/ledc.html
133 * @param[in] positive_pin 电机正极引脚编号。
134 * @param[in] positive_pin_ledc_channel 电机正极引脚对应的LED Control
135 * (LEDC)通道,共16个,范围0~15,每个pin只能对应一个通道,详情请查阅官方文档: @ref
136 * https://docs.espressif.com/projects/arduino-esp32/en/latest/api/ledc.html
137 * @param[in] negative_pin 电机负极引脚编号。
138 * @param[in] negative_pin_ledc_channel 电机负极引脚对应的LED Control
139 * (LEDC)通道,共16个,范围0~15,每个pin只能对应一个通道,详情请查阅官方文档: @ref
140 * https://docs.espressif.com/projects/arduino-esp32/en/latest/api/ledc.html
141 * @param[in] a_pin 编码器A相引脚编号。
142 * @param[in] b_pin 编码器B相引脚编号。
143 * @param[in] ppr 每转脉冲数。
144 * @param[in] reduction_ration 减速比。
145 * @param[in] phase_relation 相位关系(A相领先或B相领先,指电机正转时的情况),参数说明请查阅: @ref PhaseRelation 。
146 * @details
147 * 如果用户不清楚自己所使用的编码电机的phase_relation参数具体取值,可以使用示例程序 @ref detect_phase_relation.ino
148 * 来帮助检测确定该参数的值。
149 */
150 /**
151 * @~English
152 * @brief Constructor for creating an EncoderMotor object.
153 * @note This class will use the LED Control (LEDC) of ESP32 to generate PWM waveforms to driver the motor. When the ESP32
154 * Arduino Core version is less than 3.0.0, the ESP32 Arduino Core will not manage the LEDC channels, and the user needs to
155 * specify the LEDC channels corresponding to each pin. Therefore, it is necessary to use this constructor to construct the
156 * object and specify the LEDC channels corresponding to the positive and negative pins of the motor. Each pin can only
157 * correspond to one LEDC channel, and please do not reuse the LEDC channels. For the description of LEDC, please refer to the
158 * official website:
159 * @ref https://docs.espressif.com/projects/arduino-esp32/en/latest/api/ledc.html
160 * @param[in] positive_pin The pin number of the motor's positive pole.
161 * @param[in] positive_pin_ledc_channel The LED Control (LEDC) channel corresponding to the motor's positive pole pin, which
162 * has a total of 16 channels ranging from 0 to 15. Each pin can only correspond to one channel and is used to configure
163 * functions such as the PWM (Pulse Width Modulation) signal related to the positive pole pin of the motor. For more details,
164 * please refer to the official documentation: @ref https://docs.espressif.com/projects/arduino-esp32/en/latest/api/ledc.html
165 * @param[in] negative_pin The pin number of the motor's negative pole.
166 * @param[in] negative_pin_ledc_channel The LED Control (LEDC) channel corresponding to the motor's negative pole pin, which
167 * has a total of 16 channels ranging from 0 to 15. Each pin can only correspond to one channel and is used to configure
168 * functions such as the PWM (Pulse Width Modulation) signal related to the negative pole pin of the motor. For more details,
169 * please refer to the official documentation: @ref https://docs.espressif.com/projects/arduino-esp32/en/latest/api/ledc.html
170 * @param[in] a_pin The pin number of the encoder's A phase.
171 * @param[in] b_pin The pin number of the encoder's B phase.
172 * @param[in] ppr Pulses per revolution.
173 * @param[in] reduction_ration Reduction ratio.
174 * @param[in] phase_relation Phase relationship (A phase leads or B phase leads, referring to the situation when the motor is
175 * rotating forward), @ref PhaseRelation.
176 * @details
177 * If the user is unsure about the value of the phase_relation parameter for the encoded motor they are using, they
178 * can use the example program @ref detect_phase_relation.ino to help detect and determine the value of this parameter.
179 */
180 EncoderMotor(const uint8_t positive_pin,
181 const uint8_t positive_pin_ledc_channel,
182 const uint8_t negative_pin,
183 const uint8_t negative_pin_ledc_channel,
184 const uint8_t a_pin,
185 const uint8_t b_pin,
186 const uint32_t ppr,
187 const uint32_t reduction_ration,
188 const PhaseRelation phase_relation);
189
191
192 /**
193 * @~Chinese
194 * @brief 初始化。
195 */
196 /**
197 * @~English
198 * @brief Initialize.
199 */
200 void Init();
201
202 /**
203 * @~Chinese
204 * @brief 使用给定的比例(P)、积分(I)、微分(D)参数值来设置速度PID控制器的参数。
205 * @param[in] p 比例系数(P)的值。
206 * @param[in] i 积分系数(I)的值。
207 * @param[in] d 微分系数(D)的值。
208 */
209 /**
210 * @~English
211 * @brief Set the parameters of the speed PID controller with the given Proportional (P), Integral (I), and Derivative (D)
212 * parameter values.
213 * @param[in] p The value of the Proportional coefficient (P).
214 * @param[in] i The value of the Integral coefficient (I).
215 * @param[in] d The value of the Derivative coefficient (D).
216 */
217 void SetSpeedPid(const float p, const float i, const float d);
218
219 /**
220 * @~Chinese
221 * @brief 通过指针获取速度PID控制器的比例(P)、积分(I)、微分(D)参数值。
222 * @param[out] p 用于获取比例系数(P)值的指针,函数执行后该指针指向的内存位置将存储对应的参数值。
223 * @param[out] i 用于获取积分系数(I)值的指针,函数执行后该指针指向的内存位置将存储对应的参数值。
224 * @param[out] d 用于获取微分系数(D)值的指针,函数执行后该指针指向的内存位置将存储对应的参数值。
225 */
226 /**
227 * @~English
228 * @brief Get the Proportional (P), Integral (I), and Derivative (D) parameter values of the speed PID controller through
229 * pointers.
230 * @param[out] p Pointer used to get the value of the Proportional coefficient (P). After the function is executed, the memory
231 * location pointed to by this pointer will store the corresponding parameter value.
232 * @param[out] i Pointer used to get the value of the Integral coefficient (I). After the function is executed, the memory
233 * location pointed to by this pointer will store the corresponding parameter value.
234 * @param[out] d Pointer used to get the value of the Derivative coefficient (D). After the function is executed, the memory
235 * location pointed to by this pointer will store the corresponding parameter value.
236 */
237 void GetSpeedPid(float* const p, float* const i, float* const d) const;
238
239 /**
240 * @~Chinese
241 * @brief 直接设置电机的PWM占空比。
242 * @param[in] pwm_duty PWM占空比(取值范围 -1023到1023)。正数代表正转,负数代表反转。
243 */
244 /**
245 * @~English
246 * @brief Set motor PWM directly.
247 * @param[in] pwm_duty The duty cycle of PWM (the value range is from -1023 to 1023). A positive number represents forward
248 * rotation, and a negative number represents reverse rotation.
249 */
250 void RunPwmDuty(const int16_t pwm_duty);
251
252 /**
253 * @~Chinese
254 * @brief 以设定的速度值(RPM)运行电机。
255 * @param[in] speed_rpm 速度设定值(RPM)。
256 */
257 /**
258 * @~English
259 * @brief Run motor at speed setpoint.
260 * @param[in] speed_rpm Speed setpoint(RPM).
261 */
262 void RunSpeed(const int16_t speed_rpm);
263
264 /**
265 * @~Chinese
266 * @brief 停止电机运行。
267 */
268 /**
269 * @~English
270 * @brief Stop motor.
271 */
272 void Stop();
273
274 /**
275 * @~Chinese
276 * @brief 获取编码器脉冲计数。该计数值是在A相下降沿的时候计数,如果是正转会加一,反转则减一。
277 * @return 编码器脉冲数。
278 */
279 /**
280 * @~English
281 * @brief Get encoder pulse count. The count value is incremented by one during forward rotation and decremented by one during
282 * reverse rotation, counted at the falling edge of phase A.
283 * @return int32_t Encoder pulses.
284 */
285 int64_t EncoderPulseCount() const;
286
287 /**
288 * @~Chinese
289 * @brief 重置编码器脉冲计数为0
290 */
291 /**
292 * @~English
293 * @brief Reset the encoder pulse count to 0
294 */
295 void ResetPulseCount();
296
297 /**
298 * @~Chinese
299 * @brief 获取电机当前的转速(RPM)。
300 * @return 电机当前的转速(RPM)。
301 */
302 /**
303 * @~English
304 * @brief Get the current speed of the motor.
305 * @return The current speed of the motor in RPM.
306 */
307 int32_t SpeedRpm() const;
308
309 /**
310 * @~Chinese
311 * @brief 获取电机驱动器的PWM占空比。
312 * @return PWM占空比(取值范围 -1023到1023)。正数代表正转,负数代表反转。
313 */
314 /**
315 * @~English
316 * @brief Get the PWM pwm_duty cycle of the motor driver.
317 * @return The duty cycle of PWM (the value range is from -1023 to 1023). A positive number represents forward
318 * rotation, and a negative number represents reverse rotation.
319 */
320 int16_t PwmDuty() const;
321
322 /**
323 * @~Chinese
324 * @brief 获取电机的目标转速(RPM)。
325 * @return 电机的目标转速(RPM)。
326 */
327 /**
328 * @~English
329 * @brief Get the target speed of the motor in RPM.
330 * @return The target speed of the motor in RPM.
331 */
332 int32_t TargetRpm() const;
333
334 private:
335 static void OnPinAFalling(void* self);
336
337 void OnPinAFalling();
338
339 void UpdateRpm();
340
341 void Driving();
342
343 void DeleteThread(std::thread*& thread);
344
345 struct Pid {
346 float p = 0.0;
347 float i = 0.0;
348 float d = 0.0;
349 float integral = 0.0;
350 float max_integral = 0.0;
351 };
352
353 mutable std::mutex mutex_;
354 std::condition_variable condition_;
355 std::thread* update_rpm_thread_ = nullptr;
356 std::thread* driving_thread_ = nullptr;
357 Motor motor_driver_;
358 const uint8_t pin_a_ = 0;
359 const uint8_t pin_b_ = 0;
360 const double total_ppr_ = 0;
361 const uint8_t b_level_at_a_falling_edge_ = 0;
362 Pid rpm_pid_;
363 int64_t previous_pulse_count_ = 0;
364 std::atomic<int64_t> pulse_count_;
365 std::chrono::system_clock::time_point last_update_speed_time_ = std::chrono::time_point<std::chrono::system_clock>::min();
366 int32_t speed_rpm_ = 0;
367 int32_t target_speed_rpm_ = 0.0;
368 bool drive_ = false;
369};
370} // namespace em
371
372#endif
Encoder Motor Class.
void Init()
Initialize.
void Stop()
Stop motor.
int16_t PwmDuty() const
Get the PWM pwm_duty cycle of the motor driver.
void RunSpeed(const int16_t speed_rpm)
Run motor at speed setpoint.
void ResetPulseCount()
Reset the encoder pulse count to 0.
PhaseRelation
Used to clarify the phase relationship between phase A and phase B of the encoder when the motor is r...
@ kBPhaseLeads
Represents the situation where phase B leads phase A when the motor is rotating forward.
@ kAPhaseLeads
Represents the situation where phase A leads phase B when the motor is rotating forward.
void RunPwmDuty(const int16_t pwm_duty)
Set motor PWM directly.
int64_t EncoderPulseCount() const
Get encoder pulse count. The count value is incremented by one during forward rotation and decremente...
int32_t TargetRpm() const
Get the target speed of the motor in RPM.
void SetSpeedPid(const float p, const float i, const float d)
Set the parameters of the speed PID controller with the given Proportional (P), Integral (I),...
void GetSpeedPid(float *const p, float *const i, float *const d) const
Get the Proportional (P), Integral (I), and Derivative (D) parameter values of the speed PID controll...
EncoderMotor(const uint8_t positive_pin, const uint8_t negative_pin, const uint8_t a_pin, const uint8_t b_pin, const uint32_t ppr, const uint32_t reduction_ration, const PhaseRelation phase_relation)
Constructor for creating an EncoderMotor object.
int32_t SpeedRpm() const
Get the current speed of the motor.