kopia lustrzana https://github.com/pimoroni/pimoroni-pico
More encoder MP work
rodzic
180df9e085
commit
114c83e04e
|
@ -0,0 +1,32 @@
|
||||||
|
import gc
|
||||||
|
import time
|
||||||
|
from encoder import Encoder
|
||||||
|
# from encoder import REVERSED
|
||||||
|
|
||||||
|
"""
|
||||||
|
An example of how to read a mechanical rotary encoder, only when it has turned
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Free up hardware resources ahead of creating a new Encoder
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
# Create an encoder on the 3 ADC pins, using PIO 0 and State Machine 0
|
||||||
|
PIN_A = 26 # The A channel pin
|
||||||
|
PIN_B = 28 # The B channel pin
|
||||||
|
PIN_C = 27 # The common pin
|
||||||
|
enc = Encoder(0, 0, (PIN_A, PIN_B), PIN_C)
|
||||||
|
|
||||||
|
# Uncomment the below line (and the top import) to reverse the counting direction
|
||||||
|
# enc.direction(REVERSED)
|
||||||
|
|
||||||
|
# Loop forever
|
||||||
|
while True:
|
||||||
|
capture = enc.take_snapshot()
|
||||||
|
|
||||||
|
print("Count =", capture.count(), end=", ")
|
||||||
|
print("Angle =", capture.degrees(), end=", ")
|
||||||
|
print("Freq =", capture.frequency(), end=", ")
|
||||||
|
print("Speed =", capture.degrees_per_second())
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
import gc
|
||||||
|
from encoder import Encoder
|
||||||
|
# from encoder import REVERSED
|
||||||
|
|
||||||
|
"""
|
||||||
|
An example of how to read a mechanical rotary encoder, only when it has turned
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Free up hardware resources ahead of creating a new Encoder
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
# Create an encoder on the 3 ADC pins, using PIO 0 and State Machine 0
|
||||||
|
PIN_A = 26 # The A channel pin
|
||||||
|
PIN_B = 28 # The B channel pin
|
||||||
|
PIN_C = 27 # The common pin
|
||||||
|
enc = Encoder(0, 0, (PIN_A, PIN_B), PIN_C)
|
||||||
|
|
||||||
|
# Uncomment the below line (and the top import) to reverse the counting direction
|
||||||
|
# enc.direction(REVERSED)
|
||||||
|
|
||||||
|
# Print out the initial count, step, and turn (they should all be zero)
|
||||||
|
print("Count =", enc.count(), end=", ")
|
||||||
|
print("Step =", enc.step(), end=", ")
|
||||||
|
print("Turn =", enc.turn())
|
||||||
|
|
||||||
|
# Loop forever
|
||||||
|
while True:
|
||||||
|
if enc.delta() != 0:
|
||||||
|
# Print out the new count, step, and turn
|
||||||
|
print("Count =", enc.count(), end=", ")
|
||||||
|
print("Step =", enc.step(), end=", ")
|
||||||
|
print("Turn =", enc.turn())
|
|
@ -0,0 +1,31 @@
|
||||||
|
import gc
|
||||||
|
import time
|
||||||
|
from encoder import Encoder
|
||||||
|
# from encoder import REVERSED
|
||||||
|
|
||||||
|
"""
|
||||||
|
An example of how to read a mechanical rotary encoder.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Free up hardware resources ahead of creating a new Encoder
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
# Create an encoder on the 3 ADC pins, using PIO 0 and State Machine 0
|
||||||
|
PIN_A = 26 # The A channel pin
|
||||||
|
PIN_B = 28 # The B channel pin
|
||||||
|
PIN_C = 27 # The common pin
|
||||||
|
enc = Encoder(0, 0, (PIN_A, PIN_B), PIN_C)
|
||||||
|
|
||||||
|
# Uncomment the below line (and the top import) to reverse the counting direction
|
||||||
|
# enc.direction(REVERSED)
|
||||||
|
|
||||||
|
# Loop forever
|
||||||
|
while True:
|
||||||
|
|
||||||
|
# Print out the count, delta, step, and turn
|
||||||
|
print("Count =", enc.count(), end=", ")
|
||||||
|
print("Delta =", enc.delta(), end=", ")
|
||||||
|
print("Step =", enc.step(), end=", ")
|
||||||
|
print("Turn =", enc.turn())
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
|
@ -0,0 +1,40 @@
|
||||||
|
import gc
|
||||||
|
import time
|
||||||
|
from pimoroni import Button
|
||||||
|
from encoder import Encoder
|
||||||
|
# from encoder import REVERSED
|
||||||
|
from motor import motor2040
|
||||||
|
|
||||||
|
"""
|
||||||
|
Demonstrates how to read the counts of multiple motor encoders.
|
||||||
|
|
||||||
|
Press "Boot" to exit the program.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Free up hardware resources ahead of creating a new Encoder
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
# Create an encoder on the 3 ADC pins, using PIO 0 and State Machine 0
|
||||||
|
enc_a = Encoder(0, 0, motor2040.ENCODER_A, count_microsteps=True)
|
||||||
|
enc_b = Encoder(0, 1, motor2040.ENCODER_B, count_microsteps=True)
|
||||||
|
enc_c = Encoder(0, 2, motor2040.ENCODER_C, count_microsteps=True)
|
||||||
|
enc_d = Encoder(0, 3, motor2040.ENCODER_D, count_microsteps=True)
|
||||||
|
|
||||||
|
# Uncomment the below line (and the top import) to reverse the counting direction
|
||||||
|
# enc_a.direction(REVERSED)
|
||||||
|
# enc_b.direction(REVERSED)
|
||||||
|
# enc_c.direction(REVERSED)
|
||||||
|
# enc_d.direction(REVERSED)
|
||||||
|
|
||||||
|
# Create the user button
|
||||||
|
user_sw = Button(motor2040.USER_SW)
|
||||||
|
|
||||||
|
# Read the encoders until the user button is pressed
|
||||||
|
while user_sw.raw() is not True:
|
||||||
|
print("A =", enc_a.count(), end=", ")
|
||||||
|
print("B =", enc_b.count(), end=", ")
|
||||||
|
print("C =", enc_c.count(), end=", ")
|
||||||
|
print("D =", enc_d.count())
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
import gc
|
||||||
|
import time
|
||||||
|
from pimoroni import Button
|
||||||
|
from encoder import Encoder, MMME_CPR
|
||||||
|
# from encoder import REVERSED
|
||||||
|
from motor import motor2040
|
||||||
|
|
||||||
|
"""
|
||||||
|
Demonstrates how to read the counts of multiple motor encoders.
|
||||||
|
|
||||||
|
Press "Boot" to exit the program.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Free up hardware resources ahead of creating a new Encoder
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
# The gear ratio of the motor the encoder is attached to.
|
||||||
|
GEAR_RATIO = 50
|
||||||
|
CPR = MMME_CPR * GEAR_RATIO
|
||||||
|
|
||||||
|
|
||||||
|
# Create a list of motors
|
||||||
|
ENCODER_PINS = [ motor2040.ENCODER_A, motor2040.ENCODER_B, motor2040.ENCODER_C, motor2040.ENCODER_D ]
|
||||||
|
ENCODER_NAMES = [ "A", "B", "C", "D" ]
|
||||||
|
NUM_ENCODERS = len(ENCODER_PINS)
|
||||||
|
encoders = [Encoder(0, i, ENCODER_PINS[i], counts_per_rev=CPR, count_microsteps=True) for i in range(NUM_ENCODERS)]
|
||||||
|
|
||||||
|
# Uncomment the below line (and the top import) to reverse the counting direction
|
||||||
|
# encoders[0].direction(REVERSED)
|
||||||
|
# encoders[1].direction(REVERSED)
|
||||||
|
# encoders[2].direction(REVERSED)
|
||||||
|
# encoders[3].direction(REVERSED)
|
||||||
|
|
||||||
|
# Create the user button
|
||||||
|
user_sw = Button(motor2040.USER_SW)
|
||||||
|
|
||||||
|
captures = [None] * NUM_ENCODERS
|
||||||
|
|
||||||
|
# Read the encoders until the user button is pressed
|
||||||
|
while user_sw.raw() is not True:
|
||||||
|
# Capture the state of all encoders, at as close to the same moment as possible
|
||||||
|
for i in range(NUM_ENCODERS):
|
||||||
|
captures[i] = encoders[i].take_snapshot()
|
||||||
|
|
||||||
|
# Print out the angle and speed of each encoder
|
||||||
|
for i in range(NUM_ENCODERS):
|
||||||
|
print(ENCODER_NAMES[i], "=", captures[i].degrees(), "|", captures[i].degrees_per_second(), end=", ")
|
||||||
|
|
||||||
|
print()
|
||||||
|
time.sleep(0.1)
|
|
@ -97,6 +97,8 @@ STATIC const mp_map_elem_t encoder_globals_table[] = {
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_NORMAL), MP_ROM_INT(0x00) },
|
{ MP_ROM_QSTR(MP_QSTR_NORMAL), MP_ROM_INT(0x00) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_REVERSED), MP_ROM_INT(0x01) },
|
{ MP_ROM_QSTR(MP_QSTR_REVERSED), MP_ROM_INT(0x01) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_MMME_CPR), MP_ROM_INT(12) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_ROTARY_CPR), MP_ROM_INT(24) },
|
||||||
};
|
};
|
||||||
STATIC MP_DEFINE_CONST_DICT(mp_module_encoder_globals, encoder_globals_table);
|
STATIC MP_DEFINE_CONST_DICT(mp_module_encoder_globals, encoder_globals_table);
|
||||||
|
|
||||||
|
|
|
@ -67,32 +67,32 @@ mp_obj_t Snapshot_frequency(mp_obj_t self_in) {
|
||||||
|
|
||||||
mp_obj_t Snapshot_revolutions(mp_obj_t self_in) {
|
mp_obj_t Snapshot_revolutions(mp_obj_t self_in) {
|
||||||
_Snapshot_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Snapshot_obj_t);
|
_Snapshot_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Snapshot_obj_t);
|
||||||
return mp_obj_new_int(self->snapshot.revolutions());
|
return mp_obj_new_float(self->snapshot.revolutions());
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_t Snapshot_degrees(mp_obj_t self_in) {
|
mp_obj_t Snapshot_degrees(mp_obj_t self_in) {
|
||||||
_Snapshot_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Snapshot_obj_t);
|
_Snapshot_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Snapshot_obj_t);
|
||||||
return mp_obj_new_int(self->snapshot.degrees());
|
return mp_obj_new_float(self->snapshot.degrees());
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_t Snapshot_radians(mp_obj_t self_in) {
|
mp_obj_t Snapshot_radians(mp_obj_t self_in) {
|
||||||
_Snapshot_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Snapshot_obj_t);
|
_Snapshot_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Snapshot_obj_t);
|
||||||
return mp_obj_new_int(self->snapshot.radians());
|
return mp_obj_new_float(self->snapshot.radians());
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_t Snapshot_revolutions_delta(mp_obj_t self_in) {
|
mp_obj_t Snapshot_revolutions_delta(mp_obj_t self_in) {
|
||||||
_Snapshot_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Snapshot_obj_t);
|
_Snapshot_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Snapshot_obj_t);
|
||||||
return mp_obj_new_int(self->snapshot.revolutions_delta());
|
return mp_obj_new_float(self->snapshot.revolutions_delta());
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_t Snapshot_degrees_delta(mp_obj_t self_in) {
|
mp_obj_t Snapshot_degrees_delta(mp_obj_t self_in) {
|
||||||
_Snapshot_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Snapshot_obj_t);
|
_Snapshot_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Snapshot_obj_t);
|
||||||
return mp_obj_new_int(self->snapshot.degrees_delta());
|
return mp_obj_new_float(self->snapshot.degrees_delta());
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_t Snapshot_radians_delta(mp_obj_t self_in) {
|
mp_obj_t Snapshot_radians_delta(mp_obj_t self_in) {
|
||||||
_Snapshot_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Snapshot_obj_t);
|
_Snapshot_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Snapshot_obj_t);
|
||||||
return mp_obj_new_int(self->snapshot.radians_delta());
|
return mp_obj_new_float(self->snapshot.radians_delta());
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_t Snapshot_revolutions_per_second(mp_obj_t self_in) {
|
mp_obj_t Snapshot_revolutions_per_second(mp_obj_t self_in) {
|
||||||
|
@ -137,6 +137,10 @@ void Encoder_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t ki
|
||||||
mp_print_str(print, ", ");
|
mp_print_str(print, ", ");
|
||||||
mp_obj_print_helper(print, mp_obj_new_int(pins.b), PRINT_REPR);
|
mp_obj_print_helper(print, mp_obj_new_int(pins.b), PRINT_REPR);
|
||||||
mp_print_str(print, ", ");
|
mp_print_str(print, ", ");
|
||||||
|
uint common_pin = self->encoder->common_pin();
|
||||||
|
if(common_pin == PIN_UNUSED)
|
||||||
|
mp_print_str(print, "PIN_UNUSED");
|
||||||
|
else
|
||||||
mp_obj_print_helper(print, mp_obj_new_int(self->encoder->common_pin()), PRINT_REPR);
|
mp_obj_print_helper(print, mp_obj_new_int(self->encoder->common_pin()), PRINT_REPR);
|
||||||
mp_print_str(print, ")");
|
mp_print_str(print, ")");
|
||||||
|
|
||||||
|
@ -155,12 +159,14 @@ void Encoder_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t ki
|
||||||
mp_obj_t Encoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
mp_obj_t Encoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||||
_Encoder_obj_t *self = nullptr;
|
_Encoder_obj_t *self = nullptr;
|
||||||
|
|
||||||
enum { ARG_pio, ARG_sm, ARG_pins, ARG_common_pin, ARG_count_microsteps, ARG_freq_divider };
|
enum { ARG_pio, ARG_sm, ARG_pins, ARG_common_pin, ARG_direction, ARG_counts_per_rev, ARG_count_microsteps, ARG_freq_divider };
|
||||||
static const mp_arg_t allowed_args[] = {
|
static const mp_arg_t allowed_args[] = {
|
||||||
{ MP_QSTR_pio, MP_ARG_REQUIRED | MP_ARG_INT },
|
{ MP_QSTR_pio, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||||
{ MP_QSTR_sm, MP_ARG_REQUIRED | MP_ARG_INT },
|
{ MP_QSTR_sm, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||||
{ MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
{ MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||||
{ MP_QSTR_common_pin, MP_ARG_INT, {.u_int = PIN_UNUSED} },
|
{ MP_QSTR_common_pin, MP_ARG_INT, {.u_int = PIN_UNUSED} },
|
||||||
|
{ MP_QSTR_direction, MP_ARG_INT, {.u_int = NORMAL} },
|
||||||
|
{ MP_QSTR_counts_per_rev, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
{ MP_QSTR_count_microsteps, MP_ARG_BOOL, {.u_bool = false} },
|
{ MP_QSTR_count_microsteps, MP_ARG_BOOL, {.u_bool = false} },
|
||||||
{ MP_QSTR_freq_divider, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
{ MP_QSTR_freq_divider, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
};
|
};
|
||||||
|
@ -169,8 +175,16 @@ mp_obj_t Encoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
|
||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
PIO pio = args[ARG_pio].u_int == 0 ? pio0 : pio1;
|
int pio_int = args[ARG_pio].u_int;
|
||||||
|
if(pio_int < 0 || pio_int > (int)NUM_PIOS) {
|
||||||
|
mp_raise_ValueError("pio out of range. Expected 0 to 1");
|
||||||
|
}
|
||||||
|
PIO pio = pio_int ? pio0 : pio1;
|
||||||
|
|
||||||
int sm = args[ARG_sm].u_int;
|
int sm = args[ARG_sm].u_int;
|
||||||
|
if(sm < 0 || sm > (int)NUM_PIO_STATE_MACHINES) {
|
||||||
|
mp_raise_ValueError("sm out of range. Expected 0 to 3");
|
||||||
|
}
|
||||||
|
|
||||||
size_t pin_count = 0;
|
size_t pin_count = 0;
|
||||||
pin_pair pins;
|
pin_pair pins;
|
||||||
|
@ -208,14 +222,27 @@ mp_obj_t Encoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
|
||||||
pins.b = (uint8_t)b;
|
pins.b = (uint8_t)b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int direction = args[ARG_direction].u_int;
|
||||||
|
if(direction < 0 || direction > 1) {
|
||||||
|
mp_raise_ValueError("direction out of range. Expected NORMAL (0) or REVERSED (1)");
|
||||||
|
}
|
||||||
|
|
||||||
|
float counts_per_rev = Encoder::DEFAULT_COUNTS_PER_REV;
|
||||||
|
if(args[ARG_counts_per_rev].u_obj != mp_const_none) {
|
||||||
|
counts_per_rev = mp_obj_get_float(args[ARG_counts_per_rev].u_obj);
|
||||||
|
if(counts_per_rev < FLT_EPSILON) {
|
||||||
|
mp_raise_ValueError("counts_per_rev out of range. Expected greater than 0.0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool count_microsteps = args[ARG_count_microsteps].u_bool;
|
||||||
|
|
||||||
float freq_divider = Encoder::DEFAULT_FREQ_DIVIDER;
|
float freq_divider = Encoder::DEFAULT_FREQ_DIVIDER;
|
||||||
if(args[ARG_freq_divider].u_obj != mp_const_none) {
|
if(args[ARG_freq_divider].u_obj != mp_const_none) {
|
||||||
freq_divider = mp_obj_get_float(args[ARG_freq_divider].u_obj);
|
freq_divider = mp_obj_get_float(args[ARG_freq_divider].u_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool count_microsteps = args[ARG_count_microsteps].u_bool;
|
Encoder *encoder = new Encoder(pio, sm, pins, args[ARG_common_pin].u_int, (Direction)direction, counts_per_rev, count_microsteps, freq_divider);
|
||||||
|
|
||||||
Encoder *encoder = new Encoder(pio, sm, pins, args[ARG_common_pin].u_int, NORMAL, Encoder::DEFAULT_COUNTS_PER_REV, count_microsteps, freq_divider);
|
|
||||||
if(!encoder->init()) {
|
if(!encoder->init()) {
|
||||||
delete encoder;
|
delete encoder;
|
||||||
mp_raise_msg(&mp_type_RuntimeError, "unable to allocate the hardware resources needed to initialise this Encoder. Try running `import gc` followed by `gc.collect()` before creating it");
|
mp_raise_msg(&mp_type_RuntimeError, "unable to allocate the hardware resources needed to initialise this Encoder. Try running `import gc` followed by `gc.collect()` before creating it");
|
||||||
|
|
Ładowanie…
Reference in New Issue