33
44#include <stddef.h>
55
6+ // Helper functions
67static uint16_t degree_to_us (const servo_t * servo , float degree );
7- static void servo_init_with_cal (servo_t * servo , const pwm_output_t * pwm ,
8- uint16_t us_min , uint16_t us_mid , uint16_t us_max );
8+ static void servo_calibrate (servo_t * servo );
9+
10+ // -------- Global state --------
911
10- /* Written by task (set_servo_pair_degrees / set_gimbal_degrees); read by ISR (apply_servo_pair_degrees). */
11- static servo_pair_t servos ;
1212static volatile bool g_servo_pair_ready = false;
1313
14+ static servo_pair_t servos = {
15+ servo1 = {
16+ .us_min = SERVO1_US_MIN ,
17+ .us_max = SERVO1_US_MAX ,
18+
19+ .deg_range_max = SERVO1_DEG_RANGE_MAX ,
20+ .deg_min = SERVO_GIMBAL_DEG_MIN ,
21+ .deg_max = SERVO_GIMBAL_DEG_MAX ,
22+ .deg_bias = SERVO1_DEG_BIAS ,
23+
24+ .reversed = SERVO1_REVERSED ,
25+ .enabled = false
26+ },
27+ .servo2 = {
28+ .us_min = SERVO2_US_MIN ,
29+ .us_max = SERVO2_US_MAX ,
30+
31+ .deg_range_max = SERVO2_DEG_RANGE_MAX ,
32+ .deg_min = SERVO_GIMBAL_DEG_MIN ,
33+ .deg_max = SERVO_GIMBAL_DEG_MAX ,
34+ .deg_bias = SERVO2_DEG_BIAS ,
35+
36+ .reversed = SERVO2_REVERSED ,
37+ .enabled = false
38+ }
39+ };
40+
41+
1442/* ---- Task-level API ---------------------------------------------------- */
1543
1644void set_servo_degree (servo_t * servo , float degree ) {
@@ -24,23 +52,15 @@ void set_servo_degree(servo_t *servo, float degree) {
2452 servo -> compare_val = pwm_clamp_ticks (& servo -> pwm , ticks );
2553}
2654
27- void set_servo_pair_degrees (float degree1 , float degree2 ) {
28- if (!g_servo_pair_ready ) {
29- return ;
30- }
31- set_servo_degree (& servos .servo1 , degree1 );
32- set_servo_degree (& servos .servo2 , degree2 );
33- }
34-
3555void set_gimbal_degrees (float x_deg , float y_deg ) {
3656 if (!g_servo_pair_ready ) {
3757 return ;
3858 }
3959 /* servo1 = Y-axis (pitch); servo2 = X-axis (roll).
4060 * Negate both: positive command tilts toward positive axis per right-hand convention,
4161 * but servo mechanical direction is inverted relative to body frame. */
42- set_servo_degree (& servos .servo1 , - y_deg );
43- set_servo_degree (& servos .servo2 , - x_deg );
62+ set_servo_degree (& servos .servo1 , y_deg );
63+ set_servo_degree (& servos .servo2 , x_deg );
4464}
4565
4666/* ---- ISR-level API ----------------------------------------------------- */
@@ -55,25 +75,18 @@ void apply_servo_pair_degrees(void) {
5575
5676/* ---- Init / enable ----------------------------------------------------- */
5777
58- static void servo_init_with_cal (servo_t * servo , const pwm_output_t * pwm ,
59- uint16_t us_min , uint16_t us_mid , uint16_t us_max ) {
60- if (servo == NULL || pwm == NULL || pwm -> htim == NULL ) {
61- return ;
62- }
78+ static void servo_calibrate (servo_t * servo )
79+ {
80+ if (servo == NULL ) return ;
6381
64- servo -> pwm = * pwm ;
65- servo -> us_min = us_min ;
66- servo -> us_mid = us_mid ;
67- servo -> us_max = us_max ;
68- servo -> deg_range = SERVO_GIMBAL_RANGE_DEG ;
69- servo -> mid_pt = 0.0f ; /* 0° command = center PWM (straight down) */
70- servo -> enabled = false;
71- servo -> us_last = us_mid ;
82+ float home = degree_to_us (servo , deg_bias );
83+
84+ servo -> us_last = home ; /* Start at mid position. */
7285
7386 /* Start PWM output, set to mid position, then stop until enabled. */
7487 (void )HAL_TIM_PWM_Start (pwm -> htim , pwm -> channel );
7588 {
76- uint32_t ticks = pwm_us_to_ticks (& servo -> pwm , us_mid );
89+ uint32_t ticks = pwm_us_to_ticks (& servo -> pwm , home );
7790 ticks = pwm_clamp_ticks (& servo -> pwm , ticks );
7891 servo -> compare_val = ticks ;
7992 pwm_set_compare (& servo -> pwm , ticks );
@@ -82,12 +95,24 @@ static void servo_init_with_cal(servo_t *servo, const pwm_output_t *pwm,
8295}
8396
8497void servo_init (servo_t * servo , const pwm_output_t * pwm ) {
85- servo_init_with_cal (servo , pwm , SERVO1_US_MIN , SERVO1_US_MID , SERVO1_US_MAX );
86- }
98+ if (servo == NULL || pwm == NULL ) {
99+ return ;
100+ }
101+
102+ servo -> pwm = * pwm ;
103+
104+ servo -> us_min = SERVO1_US_MIN ;
105+ servo -> us_max = SERVO1_US_MAX ;
106+ servo -> deg_range_max = SERVO1_DEG_RANGE_MAX ;
107+
108+ servo -> deg_min = SERVO_GIMBAL_DEG_MIN ;
109+ servo -> deg_max = SERVO_GIMBAL_DEG_MAX ;
110+ servo -> deg_bias = SERVO1_DEG_BIAS ;
111+ servo -> reversed = SERVO1_REVERSED ;
87112
88- void servo_init_with_deg_range ( servo_t * servo , const pwm_output_t * pwm , float deg_range , float mid_pt ) {
89- servo_init ( servo , pwm );
90- servo_set_deg_range (servo , deg_range , mid_pt );
113+ servo -> enabled = false;
114+
115+ servo_calibrate (servo );
91116}
92117
93118void servo_enable (servo_t * servo , bool enable ) {
@@ -98,33 +123,27 @@ void servo_enable(servo_t *servo, bool enable) {
98123 servo -> enabled = enable ;
99124
100125 if (enable ) {
101- servo -> us_last = clamp_u16 (servo -> us_last , servo -> us_min , servo -> us_max );
102126 uint32_t ticks = pwm_us_to_ticks (& servo -> pwm , servo -> us_last );
103127 ticks = pwm_clamp_ticks (& servo -> pwm , ticks );
104128 pwm_set_compare (& servo -> pwm , ticks );
105129 (void )HAL_TIM_PWM_Start (servo -> pwm .htim , servo -> pwm .channel );
106130 } else {
107- uint32_t ticks = pwm_us_to_ticks (& servo -> pwm , servo -> us_mid );
131+ float home = degree_to_us (servo , deg_bias );
132+
133+ uint32_t ticks = pwm_us_to_ticks (& servo -> pwm , home );
108134 ticks = pwm_clamp_ticks (& servo -> pwm , ticks );
109135 pwm_set_compare (& servo -> pwm , ticks );
110136 (void )HAL_TIM_PWM_Stop (servo -> pwm .htim , servo -> pwm .channel );
111137 }
112138}
113139
114- void servo_set_deg_range (servo_t * servo , float deg_range , float mid_pt ) {
115- if (servo == NULL ) {
116- return ;
117- }
118- servo -> deg_range = deg_range ;
119- servo -> mid_pt = mid_pt ;
120- }
121-
122140void servo_pair_init (const pwm_output_t * pwm1 , const pwm_output_t * pwm2 ) {
123141 if (pwm1 == NULL || pwm2 == NULL ) {
124142 return ;
125143 }
126- servo_init_with_cal (& servos .servo1 , pwm1 , SERVO1_US_MIN , SERVO1_US_MID , SERVO1_US_MAX );
127- servo_init_with_cal (& servos .servo2 , pwm2 , SERVO2_US_MIN , SERVO2_US_MID , SERVO2_US_MAX );
144+
145+ servo_calibrate (& servos .servo1 );
146+ servo_calibrate (& servos .servo2 );
128147 g_servo_pair_ready = true;
129148}
130149
@@ -139,21 +158,11 @@ void servo_pair_enable(bool enable) {
139158/* ---- Static helpers ---------------------------------------------------- */
140159
141160static uint16_t degree_to_us (const servo_t * servo , float degree ) {
142- float half_range = servo -> deg_range * 0.5f ;
143- float min_deg = servo -> mid_pt - half_range ;
144- float max_deg = servo -> mid_pt + half_range ;
145- float d = clamp_float (degree , min_deg , max_deg );
146-
147- float us_f ;
148- if (d < servo -> mid_pt ) {
149- /* Negative side: [min_deg .. mid_pt] → [us_min .. us_mid] */
150- float t = (half_range > 0.0f ) ? (d - min_deg ) / half_range : 0.0f ;
151- us_f = (float )servo -> us_min + t * (float )(servo -> us_mid - servo -> us_min );
152- } else {
153- /* Positive side: [mid_pt .. max_deg] → [us_mid .. us_max] */
154- float t = (half_range > 0.0f ) ? (d - servo -> mid_pt ) / half_range : 0.0f ;
155- us_f = (float )servo -> us_mid + t * (float )(servo -> us_max - servo -> us_mid );
156- }
161+ float scale = (servo -> us_max - servo -> us_min ) / servo -> deg_range_max ;
162+
163+ float d = (servo -> reversed ? - degree : degree ) + servo -> deg_bias ;
164+ float d_clamped = clamp_float (d , servo -> deg_min , servo -> deg_max );
157165
158- return clamp_u16 ((uint16_t )(us_f + 0.5f ), servo -> us_min , servo -> us_max );
166+ uint16_t us = servo -> us_min + d_clamped * scale ;
167+ return clamp_u16 (us , servo -> us_min , servo -> us_max );
159168}
0 commit comments