@@ -185,8 +185,17 @@ class ScsServo : public stackchan::motion::Servo {
185185 int getCurrentAngle () override
186186 {
187187 int current_pos = _scs_bus.ReadPos (_config.id );
188- int angle = (current_pos - _zero_pos) * 5 * 10 / 16 ;
189- angle = uitk_intl::clamp (angle, getAngleLimit ().x , getAngleLimit ().y );
188+ if (!is_raw_pos_valid (current_pos)) {
189+ // ReadPos failure returns -1, which would map to a large bogus angle (e.g. full
190+ // deflection). Fall back to the commanded (spring) angle so callers that build a
191+ // relative move on top of getCurrentAngle() do not jerk the head to an extreme.
192+ int fallback_angle = uitk_intl::clamp (Servo::getCurrentAngle (), getAngleLimit ().x , getAngleLimit ().y );
193+ ESP_LOGW (TAG , " Servo ID: %d ignore invalid current pos: %d, fallback angle: %d" , _config.id , current_pos,
194+ fallback_angle);
195+ return fallback_angle;
196+ }
197+ int angle = raw_pos_to_angle (current_pos);
198+ angle = uitk_intl::clamp (angle, getAngleLimit ().x , getAngleLimit ().y );
190199 // ESP_LOGI(TAG, "Servo ID: %d current pos: %d angle: %d", _id, current_pos, angle);
191200 return angle;
192201 }
@@ -214,7 +223,14 @@ class ScsServo : public stackchan::motion::Servo {
214223
215224 void setCurrentAngleAsZero () override
216225 {
217- _zero_pos = _scs_bus.ReadPos (_config.id );
226+ int current_pos = _scs_bus.ReadPos (_config.id );
227+ if (!is_raw_pos_valid (current_pos)) {
228+ // A failed read here would store -1 as the zero position and corrupt calibration.
229+ ESP_LOGW (TAG , " Servo ID: %d ignore invalid zero calibration pos: %d, keep zero pos: %d" , _config.id ,
230+ current_pos, _zero_pos);
231+ return ;
232+ }
233+ _zero_pos = current_pos;
218234
219235 Settings settings (_config.settingNs , true );
220236 settings.SetInt (_config.settingZeroPositionKey , _zero_pos);
@@ -239,6 +255,16 @@ class ScsServo : public stackchan::motion::Servo {
239255private:
240256 enum class Mode { Position = 0 , PWM = 1 };
241257
258+ bool is_raw_pos_valid (int raw_pos) const
259+ {
260+ return raw_pos >= _config.rawPosLimit .x && raw_pos <= _config.rawPosLimit .y ;
261+ }
262+
263+ int raw_pos_to_angle (int raw_pos) const
264+ {
265+ return (raw_pos - _zero_pos) * 5 * 10 / 16 ;
266+ }
267+
242268 ServoConfig_t _config;
243269 int _zero_pos = 0 ;
244270 Mode _current_mode = Mode::Position;
0 commit comments