Skip to content

Commit eb3b7f7

Browse files
committed
pls work encoder
1 parent 04b7b17 commit eb3b7f7

1 file changed

Lines changed: 47 additions & 41 deletions

File tree

pybricks/experimental/pb_module_experimental.c

Lines changed: 47 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
#include "py/runtime.h"
1111
#include <math.h>
1212

13+
// Pybricks Hardware I/O Headers
1314
#include <pbio/tacho.h>
1415
#include <pbio/drivebase.h>
16+
#include <pbio/port.h>
1517

1618
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
1719
#define IS_CORTEX_M 1
@@ -21,94 +23,98 @@
2123
#define ACCEL_RAM
2224
#endif
2325

24-
// We define our own version of the objects based on the observed
25-
// memory layout of the Spike Prime firmware.
26-
typedef struct _pb_type_Motor_obj_t {
27-
mp_obj_base_t base;
28-
pbio_tacho_t *tacho;
29-
} pb_type_Motor_obj_t;
30-
31-
typedef struct _pb_type_DriveBase_obj_t {
32-
mp_obj_base_t base;
33-
pbio_drivebase_t *db;
34-
} pb_type_DriveBase_obj_t;
35-
3626
// -----------------------------------------------------------------------------
37-
// Core Math Engine
27+
// Core Math Engine (Optimized MiniMax Polynomial)
3828
// -----------------------------------------------------------------------------
3929
ACCEL_RAM static float fast_sin_internal(float theta) {
40-
float x = theta * 0.159154943f;
41-
x = theta - (float)((int)(x + (x > 0 ? 0.5f : -0.5f))) * 6.2831853f;
42-
if (x > 1.5707963f) x = 3.1415926f - x;
43-
else if (x < -1.5707963f) x = -3.1415926f - x;
30+
float x = theta * 0.159154943f; // INV_TWO_PI
31+
x = theta - (float)((int)(x + (x > 0 ? 0.5f : -0.5f))) * 6.2831853f; // TWO_PI
32+
if (x > 1.5707963f) x = 3.1415926f - x; // PI - x
33+
else if (x < -1.5707963f) x = -3.1415926f - x; // -PI - x
4434
float x2 = x * x;
4535
return x * (0.99999906f + x2 * (-0.16665554f + x2 * (0.00831190f + x2 * -0.00018488f)));
4636
}
4737

4838
// -----------------------------------------------------------------------------
49-
// High-Speed Odometry
39+
// High-Speed Hardware-Layer Odometry
5040
// -----------------------------------------------------------------------------
5141
static mp_obj_t experimental_odometry_benchmark(size_t n_args, const mp_obj_t *args) {
5242
int num_iters = mp_obj_get_int(args[0]);
5343
float wheel_circ = mp_obj_get_float(args[1]);
5444

55-
// Direct casting from the Python object to our defined struct
56-
pb_type_Motor_obj_t *m_right = (pb_type_Motor_obj_t *)MP_OBJ_TO_PTR(args[2]);
57-
pb_type_Motor_obj_t *m_left = (pb_type_Motor_obj_t *)MP_OBJ_TO_PTR(args[3]);
58-
pb_type_DriveBase_obj_t *db_obj = (pb_type_DriveBase_obj_t *)MP_OBJ_TO_PTR(args[4]);
45+
// 1. Unpack raw Port IDs from Python (e.g., ord('A') -> 65)
46+
pbio_port_id_t port_right = (pbio_port_id_t)mp_obj_get_int(args[2]);
47+
pbio_port_id_t port_left = (pbio_port_id_t)mp_obj_get_int(args[3]);
48+
49+
// 2. Bind directly to the hardware tacho drivers
50+
pbio_tacho_t *tacho_r;
51+
pbio_tacho_t *tacho_l;
52+
53+
// PBIO returns 0 (PBIO_SUCCESS) if the hardware exists on that port
54+
if (pbio_tacho_get_tacho(port_right, &tacho_r) != 0 ||
55+
pbio_tacho_get_tacho(port_left, &tacho_l) != 0) {
56+
mp_printf(&mp_plat_print, "C-ERROR: Failed to bind to hardware tachos on specified ports.\n");
57+
mp_obj_t err[5] = {mp_obj_new_float_from_f(0), mp_obj_new_int(0), mp_obj_new_float_from_f(0), mp_obj_new_float_from_f(0), mp_obj_new_float_from_f(0)};
58+
return mp_obj_new_tuple(5, err);
59+
}
60+
61+
// 3. Unpack the DriveBase heading function
62+
mp_obj_t db_heading_func = args[4];
5963

6064
float deg_to_mm = wheel_circ / 360.0f;
6165
float robot_x = 0.0f, robot_y = 0.0f;
6266

6367
pbio_angle_t ang_l, ang_r;
64-
int32_t h_mdeg;
65-
66-
// Initial capture
67-
pbio_tacho_get_angle(m_left->tacho, &ang_l);
68-
pbio_tacho_get_angle(m_right->tacho, &ang_r);
69-
pbio_drivebase_get_state_user(db_obj->db, NULL, NULL, &h_mdeg, NULL);
68+
69+
// Capture initial hardware state
70+
pbio_tacho_get_angle(tacho_l, &ang_l);
71+
pbio_tacho_get_angle(tacho_r, &ang_r);
72+
int32_t last_heading_deg = mp_obj_get_int(mp_call_function_0(db_heading_func));
7073

7174
float last_l_mm = ((float)ang_l.rotations * 360.0f + (float)ang_l.millidegrees / 1000.0f) * deg_to_mm;
7275
float last_r_mm = ((float)ang_r.rotations * 360.0f + (float)ang_r.millidegrees / 1000.0f) * deg_to_mm;
7376
float last_lin = (last_l_mm + last_r_mm) / 2.0f;
74-
float last_heading = (float)h_mdeg / 1000.0f;
7577

7678
uint32_t start_time = mp_hal_ticks_ms();
7779

7880
for (int i = 0; i < num_iters; i++) {
79-
// We use the pointers we grabbed directly from the structs
80-
pbio_tacho_get_angle(m_left->tacho, &ang_l);
81-
pbio_tacho_get_angle(m_right->tacho, &ang_r);
82-
pbio_drivebase_get_state_user(db_obj->db, NULL, NULL, &h_mdeg, NULL);
81+
// Direct C-speed hardware reads
82+
pbio_tacho_get_angle(tacho_l, &ang_l);
83+
pbio_tacho_get_angle(tacho_r, &ang_r);
84+
85+
// Single VM call for complex gyro fusion heading
86+
int32_t cur_heading_deg = mp_obj_get_int(mp_call_function_0(db_heading_func));
8387

8488
float cur_l_mm = ((float)ang_l.rotations * 360.0f + (float)ang_l.millidegrees / 1000.0f) * deg_to_mm;
8589
float cur_r_mm = ((float)ang_r.rotations * 360.0f + (float)ang_r.millidegrees / 1000.0f) * deg_to_mm;
8690
float cur_lin = (cur_l_mm + cur_r_mm) / 2.0f;
87-
float cur_heading = (float)h_mdeg / 1000.0f;
8891

8992
float linear_delta = cur_lin - last_lin;
90-
float heading_delta = cur_heading - last_heading;
93+
float heading_delta = (float)(cur_heading_deg - last_heading_deg);
9194

9295
if (fabsf(linear_delta) > 0.0001f) {
93-
float avg_h_rad = (last_heading + (heading_delta / 2.0f)) * 0.01745329f;
94-
robot_x += linear_delta * fast_sin_internal(avg_h_rad + 1.5707963f);
95-
robot_y += linear_delta * fast_sin_internal(avg_h_rad);
96+
float avg_h_rad = ((float)last_heading_deg + (heading_delta / 2.0f)) * 0.01745329f;
97+
robot_x += linear_delta * fast_sin_internal(avg_h_rad + 1.5707963f); // cos
98+
robot_y += linear_delta * fast_sin_internal(avg_h_rad); // sin
9699
}
97100

98101
last_lin = cur_lin;
99-
last_heading = cur_heading;
102+
last_heading_deg = cur_heading_deg;
100103

104+
// Yield to maintain BLE connection and reset watchdog
101105
if ((i % 2000) == 0) {
102106
mp_handle_pending(true);
103107
mp_hal_delay_ms(1);
104108
}
105109
}
106110

107111
uint32_t dur = mp_hal_ticks_ms() - start_time;
112+
float duration_s = (float)dur / 1000.0f;
113+
108114
mp_obj_t tuple[5] = {
109-
mp_obj_new_float_from_f((float)dur / 1000.0f),
115+
mp_obj_new_float_from_f(duration_s),
110116
mp_obj_new_int(num_iters),
111-
mp_obj_new_float_from_f((float)num_iters / ((float)dur / 1000.0f)),
117+
mp_obj_new_float_from_f((float)num_iters / duration_s),
112118
mp_obj_new_float_from_f(robot_x),
113119
mp_obj_new_float_from_f(robot_y)
114120
};

0 commit comments

Comments
 (0)