Skip to content

Commit 21c738d

Browse files
committed
units
1 parent 5cad2ff commit 21c738d

2 files changed

Lines changed: 51 additions & 75 deletions

File tree

pybricks/experimental/odometry.c

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
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"
@@ -16,35 +15,27 @@
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
2019
typedef 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
2725
static pbio_servo_t *left_servo_ptr = NULL;
2826
static pbio_servo_t *right_servo_ptr = NULL;
2927

30-
// Odometry State
3128
volatile bool odom_running = false;
3229
volatile uint32_t last_odom_time_ms = 0;
3330
volatile float global_x = 0.0f, global_y = 0.0f, global_h = 0.0f;
3431
volatile int32_t last_left_angle = 0, last_right_angle = 0;
3532
float odom_deg_to_mm = 1.0f;
3633
float odom_inv_track = 1.0f;
3734

38-
// Pursuit / Spline State
3935
volatile bool pursuit_running = false;
4036
volatile float p_target_speed = 0.0f;
4137
volatile 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

4940
void 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
119108
mp_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-
150133
mp_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

pybricks/experimental/platform_math.h

Lines changed: 31 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#define PYBRICKS_PLATFORM_MATH_H
33

44
#include <math.h>
5-
#include <stdint.h> // Required for uint32_t
5+
#include <stdint.h>
66

77
static inline float pb_fast_sin(float theta) {
88
float x = theta;
@@ -13,74 +13,63 @@ static inline float pb_fast_sin(float theta) {
1313
float x_wrap = theta * 0.159154943f;
1414
x = theta - (float)((int)(x_wrap + (x_wrap > 0.0f ? 0.5f : -0.5f))) * 6.2831853f;
1515
#else
16-
//loser ev3 wrap
17-
while (x > 3.14159265f) {
18-
x -= 6.28318531f;
19-
}
20-
while (x < -3.14159265f) {
21-
x += 6.28318531f;
22-
}
16+
// EV3 / ARM9 wrap
17+
while (x > 3.14159265f) x -= 6.28318531f;
18+
while (x < -3.14159265f) x += 6.28318531f;
2319
#endif
2420

25-
// 2. normalizing
26-
if (x > 1.5707963f) {
27-
x = 3.1415926f - x;
28-
} else if (x < -1.5707963f) {
29-
x = -3.1415926f - x;
30-
}
21+
// 2. Normalizing
22+
if (x > 1.5707963f) x = 3.1415926f - x;
23+
else if (x < -1.5707963f) x = -3.1415926f - x;
3124

32-
//minimax approximation
25+
// 3. Minimax approximation (Horner's method)
3326
float x2 = x * x;
34-
return x * (0.99999906f + x2 * (-0.16665554f + x2 * (0.00831190f + x2 * -0.00018488f))); //horners method to save cycles
35-
27+
return x * (0.99999906f + x2 * (-0.16665554f + x2 * (0.00831190f + x2 * -0.00018488f)));
3628
}
3729

3830
static inline float pb_fast_cos(float theta) {
3931
return pb_fast_sin(theta + 1.57079633f);
4032
}
4133

42-
// ---------------------------------------------------------
43-
// skrauzys nightmare ^1.2
44-
// ---------------------------------------------------------
45-
34+
// ----------------------------------------------------------------------------
35+
// Quake III Style - Fast Inverse Square Root (Modified for ^1.2)
36+
// ----------------------------------------------------------------------------
4637
static inline float pb_fast_pow_1_2_ultra(float x) {
4738
if (x > -0.0001f && x < 0.0001f) return 0.0f;
4839

49-
union { float f; uint32_t i; } conv;
50-
conv.f = x;
51-
52-
uint32_t i = conv.i & 0x7FFFFFFF; // evil floating point bit level hacking
53-
i &= 0x7FFFFFFF; // absolute value
54-
55-
uint32_t iy = 1278004968 - (i / 5); // what the fuck?
56-
conv.i = iy;
57-
float y = conv.f;
40+
long i;
41+
float x2, y;
42+
const float threehalfs = 1.5f;
5843

59-
float y2 = y * y;
60-
float y4 = y2 * y2;
61-
float y5 = y4 * y;
62-
float y_new = y * (1.2f - 0.2f * x * y5); // 1st iteration
63-
// y_new = y_new * ( ... ); // 2nd iteration, this can be removed
44+
x2 = x * 0.5f;
45+
y = x;
46+
i = * ( long * ) &y; // evil floating point bit level hacking
47+
i = 0x5f3759df - ( i >> 1 ); // what the fuck?
48+
y = * ( float * ) &i;
49+
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
50+
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
6451

65-
float yn2 = y_new * y_new;
52+
// Convert the inverse square root back to the ^1.2 required for the S-Curve
53+
float yn2 = y * y;
6654
float yn4 = yn2 * yn2;
67-
float x2 = x * x;
68-
69-
return x2 * yn4;
55+
return (x * x) * yn4;
7056
}
7157

72-
//skrauzys nightmare derivative
58+
// Skrauzys nightmare derivative
7359
static inline float pb_fast_s_curve_accel(float x, float a, float b, float c) {
7460
float x2 = x * x;
7561

62+
// Calculate the slope of the cubic spline
7663
float u = 3.0f * a * x2 + 2.0f * b * x + c;
7764

65+
// Calculate the second derivative (curvature numerator)
7866
float num = 6.0f * a * x + 2.0f * b;
7967

68+
// Base value for the power function
8069
float base = num / ((u * u) + 1.0f);
81-
8270

83-
return 560.0f * pb_fast_pow_1_2_ultra(base); //use the legendary hack
71+
// Apply the legendary hack to find acceleration
72+
return 560.0f * pb_fast_pow_1_2_ultra(base);
8473
}
8574

8675
#endif // PYBRICKS_PLATFORM_MATH_H

0 commit comments

Comments
 (0)