Skip to content

Commit a8cbcdb

Browse files
authored
Merge pull request #5 from GOB52/fix/servo-readpos-guard
Guard invalid ReadPos to avoid servo angle jump on bus read failure
2 parents 6216027 + aed0f7a commit a8cbcdb

1 file changed

Lines changed: 29 additions & 3 deletions

File tree

src/M5StackChan.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {
239255
private:
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

Comments
 (0)