11// SPDX-License-Identifier: MIT
22#include "py/mpconfig.h"
33
4- // This must match the flag in your mpconfigport.h
54#if PYBRICKS_PY_EXPERIMENTAL
65
76#include "py/mphal.h"
1615#include "pybricks/experimental/odometry.h"
1716#include "pybricks/experimental/platform_math.h"
1817
19- // --- THE FIX: Forward declare the Motor Object structure ---
18+ // Hardware Object structure declaration
2019typedef struct _pb_type_pupdevices_Motor_obj_t {
2120 mp_obj_base_t base ;
2221 pbio_servo_t * srv ;
2322} pb_type_pupdevices_Motor_obj_t ;
24- // -----------------------------------------------------------
2523
26- // Hardware Pointers
24+ // State Variables
2725static pbio_servo_t * left_servo_ptr = NULL ;
2826static pbio_servo_t * right_servo_ptr = NULL ;
2927
30- // Odometry State
3128volatile bool odom_running = false;
3229volatile uint32_t last_odom_time_ms = 0 ;
3330volatile float global_x = 0.0f , global_y = 0.0f , global_h = 0.0f ;
3431volatile int32_t last_left_angle = 0 , last_right_angle = 0 ;
3532float odom_deg_to_mm = 1.0f ;
3633float odom_inv_track = 1.0f ;
3734
38- // Pursuit / Spline State
3935volatile bool pursuit_running = false;
4036volatile float p_target_speed = 0.0f ;
4137volatile float p_lookahead = 120.0f ;
42-
43- // Spline Coefficients for y = ax^3 + bx^2 + cx + d
44- volatile float sp_a = 0.0f , sp_b = 0.0f , sp_c = 0.0f , sp_d = 0.0f ;
45- volatile float sp_x_end = 0.0f ;
46-
47- // --- Background Updates ---
38+ volatile float sp_a = 0.0f , sp_b = 0.0f , sp_c = 0.0f , sp_d = 0.0f , sp_x_end = 0.0f ;
4839
4940void pb_background_odometry_update (void ) {
5041 if (!odom_running || !left_servo_ptr || !right_servo_ptr ) return ;
@@ -71,6 +62,9 @@ void pb_background_odometry_update(void) {
7162 global_y += dD * pb_fast_sin (avg_h );
7263 global_h += dH ;
7364
65+ while (global_h > 3.14159f ) global_h -= 6.28318f ;
66+ while (global_h < -3.14159f ) global_h += 6.28318f ;
67+
7468 last_left_angle = cur_l ;
7569 last_right_angle = cur_r ;
7670 }
@@ -88,38 +82,32 @@ void pb_background_pursuit_update(void) {
8882
8983 float target_x = global_x + p_lookahead ;
9084 if (target_x > sp_x_end ) target_x = sp_x_end ;
91-
92- float tx2 = target_x * target_x ;
93- float tx3 = tx2 * target_x ;
94- float target_y = ( sp_a * tx3 ) + ( sp_b * tx2 ) + (sp_c * target_x ) + sp_d ;
85+
86+ float target_y = ( sp_a * ( target_x * target_x * target_x )) +
87+ ( sp_b * ( target_x * target_x )) +
88+ (sp_c * target_x ) + sp_d ;
9589
9690 float x_dif = target_x - global_x ;
9791 float y_dif = target_y - global_y ;
98- float dist_sq = (x_dif * x_dif ) + (y_dif * y_dif );
99-
10092 float relative_y = (y_dif * pb_fast_cos (global_h )) - (x_dif * pb_fast_sin (global_h ));
93+ float dist_sq = (x_dif * x_dif ) + (y_dif * y_dif );
10194
102- float m_left = 1.0f ;
103- float m_right = 1.0f ;
104-
95+ float m_left = 1.0f , m_right = 1.0f ;
10596 if (relative_y > 0.001f || relative_y < -0.001f ) {
10697 float radius = - (dist_sq / (2.0f * relative_y ));
107- float two_r = 2.0f * radius ;
10898 float track = 1.0f / odom_inv_track ;
109- m_right = two_r / (two_r + track );
110- m_left = two_r / (two_r - track );
99+ m_right = ( 2.0f * radius ) / (( 2.0f * radius ) + track );
100+ m_left = ( 2.0f * radius ) / (( 2.0f * radius ) - track );
111101 }
112102
113103 pbio_servo_run_forever (left_servo_ptr , (int32_t )(p_target_speed * m_left ));
114104 pbio_servo_run_forever (right_servo_ptr , (int32_t )(p_target_speed * m_right ));
115105}
116106
117- // --- MicroPython API ---
118-
107+ // MicroPython Wrappers
119108mp_obj_t experimental_start_odometry (size_t n_args , const mp_obj_t * args ) {
120109 left_servo_ptr = ((pb_type_pupdevices_Motor_obj_t * )MP_OBJ_TO_PTR (args [0 ]))-> srv ;
121110 right_servo_ptr = ((pb_type_pupdevices_Motor_obj_t * )MP_OBJ_TO_PTR (args [1 ]))-> srv ;
122-
123111 odom_deg_to_mm = mp_obj_get_float (args [2 ]) / 360.0f ;
124112 odom_inv_track = 1.0f / mp_obj_get_float (args [3 ]);
125113 global_x = mp_obj_get_float (args [4 ]);
@@ -142,11 +130,6 @@ mp_obj_t experimental_get_odometry(void) {
142130 return mp_obj_new_tuple (3 , tuple );
143131}
144132
145- mp_obj_t experimental_stop_odometry (void ) {
146- odom_running = false;
147- return mp_const_none ;
148- }
149-
150133mp_obj_t experimental_start_pursuit (size_t n_args , const mp_obj_t * args ) {
151134 sp_a = mp_obj_get_float (args [0 ]);
152135 sp_b = mp_obj_get_float (args [1 ]);
@@ -155,7 +138,6 @@ mp_obj_t experimental_start_pursuit(size_t n_args, const mp_obj_t *args) {
155138 sp_x_end = mp_obj_get_float (args [4 ]);
156139 p_target_speed = mp_obj_get_float (args [5 ]);
157140 p_lookahead = mp_obj_get_float (args [6 ]);
158-
159141 pursuit_running = true;
160142 return mp_const_none ;
161143}
@@ -169,4 +151,9 @@ mp_obj_t experimental_stop_pursuit(void) {
169151 return mp_const_none ;
170152}
171153
154+ mp_obj_t experimental_stop_odometry (void ) {
155+ odom_running = false;
156+ return mp_const_none ;
157+ }
158+
172159#endif // PYBRICKS_PY_EXPERIMENTAL
0 commit comments