Skip to content

Commit f48de94

Browse files
committed
reduce py overhead
1 parent 61fb450 commit f48de94

1 file changed

Lines changed: 42 additions & 47 deletions

File tree

pybricks/experimental/pb_module_experimental.c

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

13-
// Adjusted include paths to match Pybricks build system search paths
14-
#include "pybricks/pupdevices.h"
15-
#include "pybricks/robotics.h"
1613
#include <pbio/tacho.h>
14+
#include <pbio/drivebase.h>
1715

1816
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
1917
#define IS_CORTEX_M 1
@@ -23,25 +21,22 @@
2321
#define ACCEL_RAM
2422
#endif
2523

26-
// Constants
2724
static const float PI_F = 3.141592653589793f;
2825
static const float TWO_PI_F = 6.283185307179586f;
2926
static const float HALF_PI_F = 1.570796326794896f;
3027
static const float INV_TWO_PI_F = 0.159154943091895f;
3128

3229
// -----------------------------------------------------------------------------
33-
// Core Math Engine (Lasse Schlör Absolute Error Optimized)
30+
// Core Math Engine
3431
// -----------------------------------------------------------------------------
3532
ACCEL_RAM static float fast_sin_internal(float theta) {
3633
float x = theta * INV_TWO_PI_F;
3734
x = theta - (float)((int)(x + (x > 0 ? 0.5f : -0.5f))) * TWO_PI_F;
38-
3935
if (x > HALF_PI_F) {
4036
x = PI_F - x;
4137
} else if (x < -HALF_PI_F) {
4238
x = -PI_F - x;
4339
}
44-
4540
float x2 = x * x;
4641
#if IS_CORTEX_M
4742
float res = -0.0001848814f;
@@ -53,67 +48,67 @@ ACCEL_RAM static float fast_sin_internal(float theta) {
5348
#endif
5449
}
5550

56-
// Helper to safely unpack hardware values
57-
static float get_float_from_obj(mp_obj_t obj) {
58-
if (MP_OBJ_IS_SMALL_INT(obj)) {
59-
return (float)MP_OBJ_SMALL_INT_VALUE(obj);
60-
} else if (mp_obj_is_type(obj, &mp_type_float)) {
61-
return mp_obj_get_float(obj);
62-
} else {
63-
return (float)mp_obj_get_int(obj);
64-
}
65-
}
66-
6751
// -----------------------------------------------------------------------------
68-
// The "Bare Metal" Odometry Benchmark
52+
// High-Speed Bare Metal Odometry
6953
// -----------------------------------------------------------------------------
7054
static mp_obj_t experimental_odometry_benchmark(size_t n_args, const mp_obj_t *args) {
7155
int num_iters = mp_obj_get_int(args[0]);
72-
float wheel_circ = get_float_from_obj(args[1]);
56+
float wheel_circ = mp_obj_get_float(args[1]);
7357

74-
// Unpack as pointers to Pybricks objects
75-
// Note: We use the generic object pointer then cast to access members
76-
pb_type_Motor_obj_t *right_motor = (pb_type_Motor_obj_t *)MP_OBJ_TO_PTR(args[2]);
77-
pb_type_Motor_obj_t *left_motor = (pb_type_Motor_obj_t *)MP_OBJ_TO_PTR(args[3]);
78-
pb_type_DriveBase_obj_t *db = (pb_type_DriveBase_obj_t *)MP_OBJ_TO_PTR(args[4]);
58+
// We use the raw PBIO Port IDs directly to avoid struct-naming conflicts
59+
// Assuming Port A = Left, Port D = Right (Standard EV3/Spike setup)
60+
pbio_tacho_t *tacho_l = pbio_tacho_get_tacho(PBIO_PORT_ID_A);
61+
pbio_tacho_t *tacho_r = pbio_tacho_get_tacho(PBIO_PORT_ID_D);
62+
63+
// Grab the global DriveBase pointer
64+
pbio_drivebase_t *db;
65+
pbio_drivebase_get_drivebase(&db);
7966

8067
float deg_to_mm = wheel_circ / 720.0f;
8168
float robot_x = 0.0f, robot_y = 0.0f;
82-
float last_linear = 0.0f, last_heading = 0.0f;
69+
70+
pbio_angle_t ang_l, ang_r;
71+
pbio_tacho_get_angle(tacho_l, &ang_l);
72+
pbio_tacho_get_angle(tacho_r, &ang_r);
73+
74+
float last_lin = (float)ang_l.rotations * 360.0f + (float)ang_l.millidegrees / 1000.0f +
75+
(float)ang_r.rotations * 360.0f + (float)ang_r.millidegrees / 1000.0f;
76+
last_lin *= deg_to_mm;
77+
78+
int32_t h_mdeg;
79+
pbio_drivebase_get_state(db, NULL, NULL, &h_mdeg, NULL);
80+
float last_heading = (float)h_mdeg / 1000.0f;
8381

8482
uint32_t start_time = mp_hal_ticks_ms();
8583

8684
for (int i = 0; i < num_iters; i++) {
87-
int32_t r_ang, l_ang;
88-
pbio_tacho_get_angle(right_motor->tacho, &r_ang);
89-
pbio_tacho_get_angle(left_motor->tacho, &l_ang);
90-
91-
// Heading access: On many Pybricks versions, it's inside a state struct
92-
// We use the getter to be safe across EV3/Spike builds
93-
float robot_heading = pbio_drivebase_get_heading(db->db);
85+
pbio_tacho_get_angle(tacho_l, &ang_l);
86+
pbio_tacho_get_angle(tacho_r, &ang_r);
87+
pbio_drivebase_get_state(db, NULL, NULL, &h_mdeg, NULL);
9488

95-
float current_linear = (float)(r_ang + l_ang) * deg_to_mm;
96-
float linear = current_linear - last_linear;
97-
float heading_difference = robot_heading - last_heading;
89+
float cur_lin = ((float)ang_l.rotations * 360.0f + (float)ang_l.millidegrees / 1000.0f +
90+
(float)ang_r.rotations * 360.0f + (float)ang_r.millidegrees / 1000.0f) * deg_to_mm;
91+
float cur_heading = (float)h_mdeg / 1000.0f;
9892

99-
last_linear = current_linear;
100-
last_heading = robot_heading;
93+
float linear_delta = cur_lin - last_lin;
94+
float heading_delta = cur_heading - last_heading;
10195

102-
if (fabsf(linear) > 0.0f) {
103-
float avg_heading_deg = last_heading - (heading_difference / 2.0f);
104-
float avg_heading_rad = avg_heading_deg * 0.0174532925f;
105-
106-
robot_x += linear * fast_sin_internal(avg_heading_rad + HALF_PI_F);
107-
robot_y += linear * fast_sin_internal(avg_heading_rad);
96+
if (fabsf(linear_delta) > 0.001f) {
97+
float avg_h_rad = (last_heading + (heading_delta / 2.0f)) * 0.01745329f;
98+
robot_x += linear_delta * fast_sin_internal(avg_h_rad + HALF_PI_F);
99+
robot_y += linear_delta * fast_sin_internal(avg_h_rad);
108100
}
109101

102+
last_lin = cur_lin;
103+
last_heading = cur_heading;
104+
110105
if ((i % 1000) == 0) {
111106
mp_handle_pending(true);
112107
}
113108
}
114109

115-
uint32_t duration_ms = mp_hal_ticks_ms() - start_time;
116-
float duration = (float)duration_ms / 1000.0f;
110+
uint32_t dur = mp_hal_ticks_ms() - start_time;
111+
float duration = (float)dur / 1000.0f;
117112

118113
mp_obj_t tuple[5] = {
119114
mp_obj_new_float_from_f(duration),
@@ -125,7 +120,7 @@ static mp_obj_t experimental_odometry_benchmark(size_t n_args, const mp_obj_t *a
125120
return mp_obj_new_tuple(5, tuple);
126121
}
127122

128-
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(experimental_odometry_benchmark_obj, 5, 5, experimental_odometry_benchmark);
123+
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(experimental_odometry_benchmark_obj, 2, 2, experimental_odometry_benchmark);
129124

130125
static const mp_rom_map_elem_t experimental_globals_table[] = {
131126
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_experimental) },

0 commit comments

Comments
 (0)