@@ -34,191 +34,146 @@ namespace espp {
34
34
// / NOTE: on the MotorGo-Mini v1.3, the M2 motor sense is swapped in the
35
35
// / schematic, with U and W swapped
36
36
// /
37
+ // / The class is a singleton and can be accessed using the get() method.
38
+ // /
37
39
// / \section motorgo_ex1 MotorGo-Mini Example
38
40
// / \snippet motorgo_mini_example.cpp motorgo-mini example
39
41
class MotorGoMini : public BaseComponent {
40
42
public:
41
43
using Encoder = espp::Mt6701<espp::Mt6701Interface::SSI>;
42
44
using BldcMotor = espp::BldcMotor<espp::BldcDriver, Encoder>;
43
45
44
- // / Configuration for the MotorGo-Mini
45
- struct Config {
46
- bool auto_init = true ; // /< If true, the MotorGo-Mini will initialize itself in the constructor
47
- espp::Logger::Verbosity verbosity =
48
- espp::Logger::Verbosity::WARN; // /< The verbosity level for
49
- // /< the logger of the MotorGo-Mini
50
- // /< and its components
51
- };
52
-
53
- // / Constructor
54
- // / \param verbosity The verbosity level for the logger of the MotorGo-Mini
55
- // / and its components
56
- explicit MotorGoMini (espp::Logger::Verbosity verbosity = espp::Logger::Verbosity::WARN)
57
- : BaseComponent(" MotorGo-Mini" , verbosity) {
58
- always_init ();
59
- init ();
46
+ // / @brief Access the singleton instance of the MotorGoMini class
47
+ // / @return Reference to the singleton instance of the MotorGoMini class
48
+ static MotorGoMini &get () {
49
+ static MotorGoMini instance;
50
+ return instance;
60
51
}
61
52
62
- // / Constructor
63
- // / \param config The configuration for the MotorGo-Mini
64
- explicit MotorGoMini (const Config &config)
65
- : BaseComponent(" MotorGo-Mini" , config.verbosity) {
66
- always_init ();
67
- if (config.auto_init ) {
68
- init ();
69
- }
70
- }
53
+ MotorGoMini (const MotorGoMini &) = delete ;
54
+ MotorGoMini &operator =(const MotorGoMini &) = delete ;
55
+ MotorGoMini (MotorGoMini &&) = delete ;
56
+ MotorGoMini &operator =(MotorGoMini &&) = delete ;
71
57
72
58
// / Get a reference to the external I2C bus
73
59
// / \return A reference to the external I2C bus
74
- I2c &get_external_i2c () { return external_i2c_; }
60
+ I2c &get_external_i2c ();
75
61
76
62
// / Get a reference to the boot button
77
- espp::Button &button () { return button_; }
63
+ espp::Button &button ();
78
64
79
65
// / Get a reference to the yellow LED channel (channel 0)
80
66
// / \return A reference to the yellow LED channel (channel 0)
81
- espp::Led::ChannelConfig &yellow_led () { return led_channels_[0 ]; }
67
+ espp::Led::ChannelConfig &yellow_led ();
68
+
82
69
// / Get a reference to the yellow LED channel (channel 0)
83
70
// / \return A reference to the yellow LED channel (channel 0)
84
- espp::Led::ChannelConfig &led_channel0 () { return led_channels_[0 ]; }
71
+ espp::Led::ChannelConfig &led_channel0 ();
72
+
85
73
// / Set the duty cycle of the yellow LED
86
74
// / \param duty The duty cycle of the yellow LED (0.0 - 100.0)
87
75
// / \note The duty cycle is a percentage of the maximum duty cycle
88
76
// / (which is 100.0)
89
77
// / 0.0 is off, 100.0 is fully on
90
78
// / \note For this function to have an effect, the LED timer must NOT be running
91
79
// / (i.e. stop_breathing() must be called)
92
- void set_yellow_led_duty (float duty) { led_. set_duty (led_channels_[ 0 ]. channel , duty); }
80
+ void set_yellow_led_duty (float duty);
93
81
94
82
// / Get a reference to the red LED channel (channel 1)
95
83
// / \return A reference to the red LED channel (channel 1)
96
- espp::Led::ChannelConfig &red_led () { return led_channels_[1 ]; }
84
+ espp::Led::ChannelConfig &red_led ();
85
+
97
86
// / Get a reference to the red LED channel (channel 1)
98
87
// / \return A reference to the red LED channel (channel 1)
99
- espp::Led::ChannelConfig &led_channel1 () { return led_channels_[1 ]; }
88
+ espp::Led::ChannelConfig &led_channel1 ();
89
+
100
90
// / Set the duty cycle of the red LED
101
91
// / \param duty The duty cycle of the red LED (0.0 - 100.0)
102
92
// / \note The duty cycle is a percentage of the maximum duty cycle
103
93
// / (which is 100.0)
104
94
// / 0.0 is off, 100.0 is fully on
105
95
// / \note For this function to have an effect, the LED timer must NOT be running
106
96
// / (i.e. stop_breathing() must be called)
107
- void set_red_led_duty (float duty) { led_. set_duty (led_channels_[ 1 ]. channel , duty); }
97
+ void set_red_led_duty (float duty);
108
98
109
99
// / Get a reference to the LED object which controls the LEDs
110
100
// / \return A reference to the Led object
111
- espp::Led &led () { return led_; }
101
+ espp::Led &led ();
112
102
113
103
// / \brief Get a reference to the Gaussian object which is used for breathing
114
104
// / the LEDs.
115
105
// / \return A reference to the Gaussian object
116
- espp::Gaussian &gaussian () { return gaussian_; }
106
+ espp::Gaussian &gaussian ();
117
107
118
108
// / Start breathing the LEDs
119
109
// / \details This function starts the LED timer which will periodically update
120
110
// / the LED duty cycle using the gaussian to create a breathing
121
111
// / efect.
122
- void start_breathing () {
123
- io38_breathe_start_us = esp_timer_get_time ();
124
- io8_breathe_start_us = esp_timer_get_time ();
125
- static constexpr uint64_t led_timer_period_us = 30 * 1000 ; // 30 ms
126
- led_timer_.periodic (led_timer_period_us);
127
- }
112
+ void start_breathing ();
128
113
129
114
// / Stop breathing the LEDs
130
115
// / \details This function stops the LED timer which will stop updating the
131
116
// / LED duty cycle. It will also set the LED duty cycle to 0,
132
117
// / effectively turning off the LEDs.
133
- void stop_breathing () {
134
- led_timer_.stop ();
135
- led_.set_duty (led_channels_[0 ].channel , 0 .0f );
136
- led_.set_duty (led_channels_[1 ].channel , 0 .0f );
137
- }
118
+ void stop_breathing ();
138
119
139
120
// / Initialize the MotorGo-Mini's components for motor channel 1
140
121
// / \details This function initializes the encoder and motor for motor channel
141
122
// / 1. This consists of initializing encoder1 and motor1.
142
- void init_motor_channel_1 () {
143
- bool run_task = true ;
144
- std::error_code ec;
145
- encoder1_.initialize (run_task, ec);
146
- if (ec) {
147
- logger_.error (" Could not initialize encoder1: {}" , ec.message ());
148
- return ;
149
- }
150
- motor1_.initialize ();
151
- }
123
+ void init_motor_channel_1 ();
152
124
153
125
// / Initialize the MotorGo-Mini's components for motor channel 2
154
126
// / \details This function initializes the encoder and motor for motor channel
155
127
// / 2. This consists of initializing encoder2 and motor2.
156
- void init_motor_channel_2 () {
157
- bool run_task = true ;
158
- std::error_code ec;
159
- encoder2_.initialize (run_task, ec);
160
- if (ec) {
161
- logger_.error (" Could not initialize encoder2: {}" , ec.message ());
162
- return ;
163
- }
164
- motor2_.initialize ();
165
- }
128
+ void init_motor_channel_2 ();
166
129
167
130
// / Get a reference to the encoder 1
168
131
// / \return A reference to the encoder 1
169
- Encoder &encoder1 () { return encoder1_; }
132
+ Encoder &encoder1 ();
170
133
171
134
// / Get a reference to the encoder 2
172
135
// / \return A reference to the encoder 2
173
- Encoder &encoder2 () { return encoder2_; }
136
+ Encoder &encoder2 ();
174
137
175
138
// / Get a reference to the motor 1 driver
176
139
// / \return A reference to the motor 1 driver
177
- espp::BldcDriver &motor1_driver () { return motor1_driver_; }
140
+ espp::BldcDriver &motor1_driver ();
178
141
179
142
// / Get a reference to the motor 2 driver
180
143
// / \return A reference to the motor 2 driver
181
- espp::BldcDriver &motor2_driver () { return motor2_driver_; }
144
+ espp::BldcDriver &motor2_driver ();
182
145
183
146
// / Get a reference to the motor 1
184
147
// / \return A reference to the motor 1
185
- BldcMotor &motor1 () { return motor1_; }
148
+ BldcMotor &motor1 ();
186
149
187
150
// / Get a reference to the motor 2
188
151
// / \return A reference to the motor 2
189
- BldcMotor &motor2 () { return motor2_; }
152
+ BldcMotor &motor2 ();
190
153
191
154
// / Get a reference to the ADC_UNIT_1 OneshotAdc object
192
155
// / \return A reference to the ADC_UNIT_1 OneshotAdc object
193
- espp::OneshotAdc &adc1 () { return adc_1; }
156
+ espp::OneshotAdc &adc1 ();
194
157
195
158
// / Get a reference to the ADC_UNIT_2 OneshotAdc object
196
159
// / \return A reference to the ADC_UNIT_2 OneshotAdc object
197
- espp::OneshotAdc &adc2 () { return adc_2; }
160
+ espp::OneshotAdc &adc2 ();
198
161
199
162
// / Get the current sense value for motor 1 phase U
200
163
// / \return The current sense value for motor 1 phase U in amps
201
- float motor1_current_u_amps () {
202
- return adc_1.read_mv (current_sense_m1_u_).value () * CURRENT_SENSE_MV_TO_A;
203
- }
164
+ float motor1_current_u_amps ();
204
165
205
166
// / Get the current sense value for motor 1 phase W
206
167
// / \return The current sense value for motor 1 phase W in amps
207
- float motor1_current_w_amps () {
208
- return adc_1.read_mv (current_sense_m1_w_).value () * CURRENT_SENSE_MV_TO_A;
209
- }
168
+ float motor1_current_w_amps ();
210
169
211
170
// / Get the current sense value for motor 2 phase U
212
171
// / \return The current sense value for motor 2 phase U in amps
213
- float motor2_current_u_amps () {
214
- return adc_2.read_mv (current_sense_m2_u_).value () * CURRENT_SENSE_MV_TO_A;
215
- }
172
+ float motor2_current_u_amps ();
216
173
217
174
// / Get the current sense value for motor 2 phase W
218
175
// / \return The current sense value for motor 2 phase W in amps
219
- float motor2_current_w_amps () {
220
- return adc_1.read_mv (current_sense_m2_w_).value () * CURRENT_SENSE_MV_TO_A;
221
- }
176
+ float motor2_current_w_amps ();
222
177
223
178
protected:
224
179
static constexpr auto I2C_PORT = I2C_NUM_0;
@@ -254,121 +209,15 @@ class MotorGoMini : public BaseComponent {
254
209
// TODO: figure this out and update it :)
255
210
static constexpr float CURRENT_SENSE_MV_TO_A = 1 .0f ;
256
211
257
- void always_init () {
258
- start_breathing ();
259
- init_spi ();
260
- }
261
-
262
- void init () {
263
- init_encoders ();
264
- init_motors ();
265
- }
266
-
267
- void init_spi () {
268
- // Initialize the SPI bus for the encoders
269
- memset (&encoder_spi_bus_config_, 0 , sizeof (encoder_spi_bus_config_));
270
- encoder_spi_bus_config_.mosi_io_num = -1 ;
271
- encoder_spi_bus_config_.miso_io_num = ENCODER_SPI_MISO_PIN;
272
- encoder_spi_bus_config_.sclk_io_num = ENCODER_SPI_SCLK_PIN;
273
- encoder_spi_bus_config_.quadwp_io_num = -1 ;
274
- encoder_spi_bus_config_.quadhd_io_num = -1 ;
275
- encoder_spi_bus_config_.max_transfer_sz = 100 ;
276
- // encoder_spi_bus_config_.isr_cpu_id = 0; // set to the same core as the esp-timer task (which
277
- // runs the encoders)
278
- auto err = spi_bus_initialize (ENCODER_SPI_HOST, &encoder_spi_bus_config_, SPI_DMA_CH_AUTO);
279
- if (err != ESP_OK) {
280
- logger_.error (" Failed to initialize SPI bus for encoders: {}" , esp_err_to_name (err));
281
- return ;
282
- }
283
-
284
- // Initialize the encoder 1
285
- memset (&encoder1_config, 0 , sizeof (encoder1_config));
286
- encoder1_config.mode = 0 ;
287
- encoder1_config.clock_speed_hz = ENCODER_SPI_CLK_SPEED;
288
- encoder1_config.queue_size = 1 ;
289
- encoder1_config.spics_io_num = ENCODER_1_CS_PIN;
290
- // encoder1_config.cs_ena_pretrans = 2;
291
- // encoder1_config.input_delay_ns = 30;
292
- err = spi_bus_add_device (ENCODER_SPI_HOST, &encoder1_config, &encoder1_handle_);
293
- if (err != ESP_OK) {
294
- logger_.error (" Failed to initialize Encoder 1: {}" , esp_err_to_name (err));
295
- return ;
296
- }
297
-
298
- // Initialize the encoder 2
299
- memset (&encoder2_config, 0 , sizeof (encoder2_config));
300
- encoder2_config.mode = 0 ;
301
- encoder2_config.clock_speed_hz = ENCODER_SPI_CLK_SPEED;
302
- encoder2_config.queue_size = 1 ;
303
- encoder2_config.spics_io_num = ENCODER_2_CS_PIN;
304
- // encoder2_config.cs_ena_pretrans = 2;
305
- // encoder2_config.input_delay_ns = 30;
306
- err = spi_bus_add_device (ENCODER_SPI_HOST, &encoder2_config, &encoder2_handle_);
307
- if (err != ESP_OK) {
308
- logger_.error (" Failed to initialize Encoder 2: {}" , esp_err_to_name (err));
309
- return ;
310
- }
311
- }
212
+ // / Constructor
213
+ MotorGoMini ();
312
214
313
- void init_encoders () {
314
- bool run_task = true ;
315
- std::error_code ec;
316
- encoder1_.initialize (run_task, ec);
317
- if (ec) {
318
- logger_.error (" Could not initialize encoder1: {}" , ec.message ());
319
- }
320
- ec.clear ();
321
- encoder2_.initialize (run_task, ec);
322
- if (ec) {
323
- logger_.error (" Could not initialize encoder2: {}" , ec.message ());
324
- }
325
- ec.clear ();
326
- }
215
+ void always_init ();
216
+ void init_spi ();
327
217
328
- void init_motors () {
329
- motor1_.initialize ();
330
- motor2_.initialize ();
331
- }
218
+ float breathe (float breathing_period, uint64_t start_us, bool restart = false );
332
219
333
- float breathe (float breathing_period, uint64_t start_us, bool restart = false ) {
334
- auto now_us = esp_timer_get_time ();
335
- if (restart) {
336
- start_us = now_us;
337
- }
338
- auto elapsed_us = now_us - start_us;
339
- float elapsed = elapsed_us / 1e6f;
340
- float t = std::fmod (elapsed, breathing_period) / breathing_period;
341
- return gaussian_ (t);
342
- }
343
-
344
- bool IRAM_ATTR read_encoder (const auto &encoder_handle, uint8_t *data, size_t size) {
345
- static constexpr uint8_t SPIBUS_READ = 0x80 ;
346
- spi_transaction_t t = {
347
- .flags = 0 ,
348
- .cmd = 0 ,
349
- .addr = SPIBUS_READ,
350
- .length = size * 8 ,
351
- .rxlength = size * 8 ,
352
- .user = nullptr ,
353
- .tx_buffer = nullptr ,
354
- .rx_buffer = data,
355
- };
356
- if (size <= 4 ) {
357
- t.flags = SPI_TRANS_USE_RXDATA;
358
- t.rx_buffer = nullptr ;
359
- }
360
- esp_err_t err = spi_device_polling_transmit (encoder_handle, &t);
361
- if (err != ESP_OK) {
362
- return false ;
363
- }
364
- if (size <= 4 ) {
365
- // copy the data from the rx_data field
366
- for (size_t i = 0 ; i < size; i++) {
367
- data[i] = t.rx_data [i];
368
- }
369
- }
370
- return true ;
371
- }
220
+ bool read_encoder (const auto &encoder_handle, uint8_t *data, size_t size);
372
221
373
222
// / I2C bus for external communication
374
223
I2c external_i2c_{{.port = I2C_PORT,
0 commit comments