11// SPDX-License-Identifier: MIT
22#include "py/mpconfig.h"
3+
4+ #if PYBRICKS_PY_EXPERIMENTAL
5+
36#include "py/mphal.h"
47#include "py/runtime.h"
58#include <math.h>
6- #include "pybricks/experimental/platform_math.h"
9+
10+ // Core Pybricks headers for bare-metal hardware access
11+ #include <pybricks/common.h>
12+ #include <pbio/servo.h>
713#include "pybricks/experimental/odometry.h"
814
9- mp_obj_t calculate_odometry (int num_iters , float wheel_circ , float axle_track , mp_obj_t right_angle_func , mp_obj_t left_angle_func ) {
10- float deg_to_mm = wheel_circ * 0.0027777778f ;
15+ // Hardware acceleration for the Spike Prime (FPU + RAM execution)
16+ #if defined(__ARM_ARCH_7M__ ) || defined(__ARM_ARCH_7EM__ )
17+ #define ACCEL_RAM __attribute__((section(".data"), noinline))
18+ #else
19+ #define ACCEL_RAM
20+ #endif
21+
22+ ACCEL_RAM static float fast_sin_internal (float theta ) {
23+ float x = theta * 0.159154943f ;
24+ x = theta - (float )((int )(x + (x > 0.00f ? 0.5f : -0.5f ))) * 6.2831853f ;
25+
26+ if (x > 1.5707963f ) {
27+ x = 3.1415926f - x ;
28+ } else if (x < -1.5707963f ) {
29+ x = -3.1415926f - x ;
30+ }
31+
32+ float x2 = x * x ;
33+ return x * (0.99999906f + x2 * (-0.16665554f + x2 * (0.00831190f + x2 * -0.00018488f )));
34+ }
35+
36+ mp_obj_t calculate_odometry (int num_iters , float wheel_circ , float axle_track , mp_obj_t right_motor_obj , mp_obj_t left_motor_obj ) {
37+
38+ float deg_to_mm = wheel_circ * 0.0027777778f ;
1139 float inv_axle_track = 1.0f / axle_track ;
12- float rx = 0.0f , ry = 0.0f , rh = 0.0f ;
1340
14- int32_t last_r = mp_obj_get_int (mp_call_function_0 (right_angle_func ));
15- int32_t last_l = mp_obj_get_int (mp_call_function_0 (left_angle_func ));
41+ float rx = 0.0f ;
42+ float ry = 0.0f ;
43+ float rh = 0.0f ;
44+
45+ // THE MAGIC: Extract the raw Pybricks hardware struct from the Python object.
46+ // This entirely removes the Python interpreter from the loop.
47+ pbio_servo_t * srv_r = ((pb_type_Motor_obj_t * )MP_OBJ_TO_PTR (right_motor_obj ))-> srv ;
48+ pbio_servo_t * srv_l = ((pb_type_Motor_obj_t * )MP_OBJ_TO_PTR (left_motor_obj ))-> srv ;
49+
50+ int32_t last_r , last_l , unused_rate ;
51+ // Direct memory read to initialize
52+ pbio_servo_get_state_user (srv_r , & last_r , & unused_rate );
53+ pbio_servo_get_state_user (srv_l , & last_l , & unused_rate );
54+
1655 uint32_t start_time = mp_hal_ticks_ms ();
1756
1857 for (int i = 0 ; i < num_iters ; i ++ ) {
19- int32_t cur_r = mp_obj_get_int (mp_call_function_0 (right_angle_func ));
20- int32_t cur_l = mp_obj_get_int (mp_call_function_0 (left_angle_func ));
58+ int32_t cur_r , cur_l ;
59+
60+ // 1. Direct memory read (Instantaneous, 0 Python overhead)
61+ pbio_servo_get_state_user (srv_r , & cur_r , & unused_rate );
62+ pbio_servo_get_state_user (srv_l , & cur_l , & unused_rate );
2163
64+ // 2. FPU Delta Math
2265 float dR = (float )(cur_r - last_r ) * deg_to_mm ;
2366 float dL = (float )(cur_l - last_l ) * deg_to_mm ;
2467 float dD = (dR + dL ) * 0.5f ;
2568 float dH = (dR - dL ) * inv_axle_track ;
2669
70+ // 3. RK2 Integration
2771 if (dD != 0.0f || dH != 0.0f ) {
2872 float avg_h = rh + (dH * 0.5f );
29- rx += dD * pb_fast_cos (avg_h );
30- ry += dD * pb_fast_sin (avg_h );
73+ rx += dD * fast_sin_internal (avg_h + 1.5707963f ); // cos
74+ ry += dD * fast_sin_internal (avg_h ); // sin
3175 rh += dH ;
3276 }
77+
3378 last_r = cur_r ;
3479 last_l = cur_l ;
3580
81+ // 4. Polling (bitwise check is faster than modulo)
3682 if ((i & 0x3FF ) == 0 ) {
3783 mp_handle_pending (true);
3884 }
3985 }
4086
4187 uint32_t dur = mp_hal_ticks_ms () - start_time ;
88+
4289 mp_obj_t tuple [5 ] = {
4390 mp_obj_new_float_from_f ((float )dur * 0.001f ),
4491 mp_obj_new_int (num_iters ),
@@ -48,3 +95,35 @@ mp_obj_t calculate_odometry(int num_iters, float wheel_circ, float axle_track, m
4895 };
4996 return mp_obj_new_tuple (5 , tuple );
5097}
98+
99+ // Optimized Pure Pursuit Logic using Dot Products
100+ mp_obj_t get_pure_pursuit_multipliers (float tx , float ty , float rx_pos , float ry_pos , float rh_ang , float track ) {
101+ float x_dif = tx - rx_pos ;
102+ float y_dif = ty - ry_pos ;
103+
104+ float cos_h = fast_sin_internal (rh_ang + 1.5707963f );
105+ float sin_h = fast_sin_internal (rh_ang );
106+
107+ float relative_y = (y_dif * cos_h ) - (x_dif * sin_h );
108+
109+ float m_left = 1.0f ;
110+ float m_right = 1.0f ;
111+
112+ float abs_rel_y = relative_y < 0.0f ? - relative_y : relative_y ;
113+
114+ if (abs_rel_y > 0.001f ) {
115+ float dist_sq = (x_dif * x_dif ) + (y_dif * y_dif );
116+ float radius = - (dist_sq / (2.0f * relative_y ));
117+ float two_r = 2.0f * radius ;
118+ m_right = two_r / (two_r + track );
119+ m_left = two_r / (two_r - track );
120+ }
121+
122+ mp_obj_t tuple [2 ] = {
123+ mp_obj_new_float_from_f (m_left ),
124+ mp_obj_new_float_from_f (m_right )
125+ };
126+ return mp_obj_new_tuple (2 , tuple );
127+ }
128+
129+ #endif
0 commit comments