Skip to content

Commit af43171

Browse files
committed
pbio/drv/counter_ev3: Detect type while stationary.
By updating the stable type ID only while stationary, we suppress noisy readings while rotating. This also refactors the code slightly for clarity. Fixes pybricks/support#2536
1 parent b375f3f commit af43171

2 files changed

Lines changed: 68 additions & 37 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@
2323
- Devices like the `Remote`, `LWP3Device`, and the `XboxController` now stay
2424
connected when the program ends ([support#1382]).
2525

26+
### Fixed
27+
- Fixed EV3 motor detection not working correctly while moving ([support#2536]).
28+
2629
[support#1382]: https://github.com/pybricks/support/issues/1382
2730
[support#1800]: https://github.com/pybricks/support/issues/1800
31+
[support#2536]: https://github.com/pybricks/support/issues/2536
2832
[pybricks-micropython#454]: https://github.com/pybricks/pybricks-micropython/pull/454
2933

3034
## [4.0.0b5] - 2026-01-30

lib/pbio/drv/counter/counter_ev3.c

Lines changed: 64 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -40,40 +40,68 @@
4040
#endif
4141

4242
struct _pbdrv_counter_dev_t {
43-
int32_t count;
43+
/**
44+
* Position of the motor in degrees.
45+
*/
46+
int32_t position;
47+
/**
48+
* Quadrature int pin.
49+
*/
4450
pbdrv_gpio_t gpio_int;
51+
/**
52+
* Quadrature dir pin.
53+
*/
4554
pbdrv_gpio_t gpio_dir;
55+
/**
56+
* Additional GPIO for device detection (not used).
57+
*/
4658
pbdrv_gpio_t gpio_det;
59+
/**
60+
* ADC channel for device detection.
61+
*/
4762
uint8_t adc_channel;
63+
/**
64+
* Last instantaneous ADC device detection.
65+
*/
4866
lego_device_type_id_t last_type_id;
67+
/**
68+
* Stable device detection.
69+
*/
4970
lego_device_type_id_t stable_type_id;
71+
/**
72+
* How many times the same type ID was found sequentially.
73+
*/
5074
uint32_t type_id_count;
75+
/**
76+
* The position at which the type ID detection was started.
77+
*/
78+
int32_t type_id_position;
5179
};
5280

5381
static pbdrv_counter_dev_t counters[] = {
5482
{
55-
.count = 0,
83+
.position = 0,
5684
.gpio_int = PBDRV_GPIO_EV3_PIN(11, 19, 16, 5, 11),
5785
.gpio_dir = PBDRV_GPIO_EV3_PIN(1, 15, 12, 0, 4),
5886
.gpio_det = PBDRV_GPIO_EV3_PIN(12, 15, 12, 5, 4),
5987
.adc_channel = 1,
6088
},
6189
{
62-
.count = 0,
90+
.position = 0,
6391
.gpio_int = PBDRV_GPIO_EV3_PIN(11, 31, 28, 5, 8),
6492
.gpio_dir = PBDRV_GPIO_EV3_PIN(5, 27, 24, 2, 9),
6593
.gpio_det = PBDRV_GPIO_EV3_PIN(6, 11, 8, 2, 5),
6694
.adc_channel = 0,
6795
},
6896
{
69-
.count = 0,
97+
.position = 0,
7098
.gpio_int = PBDRV_GPIO_EV3_PIN(11, 11, 8, 5, 13),
7199
.gpio_dir = PBDRV_GPIO_EV3_PIN(7, 7, 4, 3, 14),
72100
.gpio_det = PBDRV_GPIO_EV3_PIN(7, 31, 28, 3, 8),
73101
.adc_channel = 13,
74102
},
75103
{
76-
.count = 0,
104+
.position = 0,
77105
.gpio_int = PBDRV_GPIO_EV3_PIN(13, 27, 24, 6, 9),
78106
.gpio_dir = PBDRV_GPIO_EV3_PIN(5, 31, 28, 2, 8),
79107
.gpio_det = PBDRV_GPIO_EV3_PIN(11, 3, 0, 5, 15),
@@ -113,9 +141,6 @@ static bool adc_is_close(uint32_t adc, uint32_t reference) {
113141
* The original firmware uses a dynamic process to distinguish other non-motor
114142
* devices. This is not implemented here. It does not appear necessary for
115143
* motors.
116-
*
117-
* If we find that we occasionally get "in-between" values, we can have the
118-
* adc process poll us to maintain a minium count of unchanged states.
119144
*/
120145
static lego_device_type_id_t pbdrv_counter_ev3_get_type(uint16_t adc) {
121146

@@ -128,7 +153,10 @@ static lego_device_type_id_t pbdrv_counter_ev3_get_type(uint16_t adc) {
128153
}
129154

130155
if (adc_is_close(adc, ADC_EV3_LARGE_0) || adc_is_close(adc, ADC_EV3_LARGE_1) || adc_is_close(adc, ADC_NXT_LARGE_1)) {
131-
return LEGO_DEVICE_TYPE_ID_NXT_MOTOR;
156+
// We can only detect the difference between NXT and EV3 motors 50% of
157+
// the time, depending on the optical encoder state. So always return
158+
// the same type for consistency. Their parameters are relatively close.
159+
return LEGO_DEVICE_TYPE_ID_EV3_LARGE_MOTOR;
132160
}
133161

134162
return LEGO_DEVICE_TYPE_ID_NONE;
@@ -140,29 +168,26 @@ static lego_device_type_id_t pbdrv_counter_ev3_get_type(uint16_t adc) {
140168
/**
141169
* Updates the type of all EV3 motors based on the current ADC values.
142170
*/
143-
static void pbdrv_counter_ev3_update_type(void) {
144-
145-
for (uint8_t i = 0; i < PBIO_ARRAY_SIZE(counters); i++) {
146-
147-
// Get type detected now.
148-
pbdrv_counter_dev_t *dev = &counters[i];
149-
uint16_t adc = 0;
150-
pbdrv_adc_get_ch(dev->adc_channel, &adc);
151-
lego_device_type_id_t type_id = pbdrv_counter_ev3_get_type(adc);
152-
153-
// Update number of consecutive identical detections.
154-
if (dev->last_type_id == type_id) {
155-
dev->type_id_count++;
156-
} else {
157-
dev->last_type_id = type_id;
158-
dev->type_id_count = 1;
159-
}
171+
static void pbdrv_counter_ev3_update_type(pbdrv_counter_dev_t *dev) {
172+
173+
// Get type detected now.
174+
uint16_t adc = 0;
175+
pbdrv_adc_get_ch(dev->adc_channel, &adc);
176+
lego_device_type_id_t type_id = pbdrv_counter_ev3_get_type(adc);
177+
178+
// Update number of consecutive identical detections.
179+
if (dev->last_type_id == type_id && dev->position == dev->type_id_position) {
180+
dev->type_id_count++;
181+
} else {
182+
dev->last_type_id = type_id;
183+
dev->type_id_count = 1;
184+
dev->type_id_position = dev->position;
185+
}
160186

161-
// Update stable type if we have seen enough identical detections,
162-
// including none detections.
163-
if (dev->type_id_count >= PBDRV_COUNTER_EV3_TYPE_MIN_STABLE_COUNT) {
164-
dev->stable_type_id = type_id;
165-
}
187+
// Update stable type if we have seen enough identical detections,
188+
// including none detections.
189+
if (dev->type_id_count >= PBDRV_COUNTER_EV3_TYPE_MIN_STABLE_COUNT) {
190+
dev->stable_type_id = type_id;
166191
}
167192
}
168193

@@ -178,7 +203,9 @@ static pbio_error_t pbdrv_counter_device_detect_process_thread(pbio_os_state_t *
178203
PBIO_OS_ASYNC_BEGIN(state);
179204

180205
for (;;) {
181-
pbdrv_counter_ev3_update_type();
206+
for (uint8_t i = 0; i < PBIO_ARRAY_SIZE(counters); i++) {
207+
pbdrv_counter_ev3_update_type(&counters[i]);
208+
}
182209
PBIO_OS_AWAIT_MS(state, &timer, PBDRV_COUNTER_EV3_TYPE_LOOP_TIME);
183210
}
184211

@@ -210,8 +237,8 @@ pbio_error_t pbdrv_counter_get_angle(pbdrv_counter_dev_t *dev, int32_t *rotation
210237
return err;
211238
}
212239

213-
*millidegrees = (dev->count % 360) * 1000;
214-
*rotations = dev->count / 360;
240+
*millidegrees = (dev->position % 360) * 1000;
241+
*rotations = dev->position / 360;
215242
return PBIO_SUCCESS;
216243
}
217244

@@ -234,12 +261,12 @@ static void pbdrv_counter_ev3_irq_handler(uint32_t bank_id, uint32_t bank_int_id
234261
continue;
235262
}
236263

237-
// Clear the interrupt and update the count.
264+
// Clear the interrupt and update the position.
238265
HWREG(SOC_GPIO_0_REGS + GPIO_INTSTAT((bank_id / 2))) = mask;
239266
if (pbdrv_gpio_input(&dev->gpio_int) ^ pbdrv_gpio_input(&dev->gpio_dir)) {
240-
dev->count++;
267+
dev->position++;
241268
} else {
242-
dev->count--;
269+
dev->position--;
243270
}
244271
}
245272

0 commit comments

Comments
 (0)