How to unbrick STS3215 servo motor?

Hi!

I am using ESP32 and STS3215 servos in my robotic arm project. If during movement my servo meets an obstacle my code switches it into holding mode. With a brand new servo it works pretty well but after a while servo just stops moving at all, it's built in LED blinks, servo responds to Ping/ReadPos/ReadLoad commands from WaveShares Library but does not move at all. The only suspicious thing I see is that ReadVoltage shows 0mV but multiple different testers show clearly that there are 6V on servo's input pins.

Here is the code that I use to move the servo. If anyone knows what happened to my servos and knows how to restore or prevent this from happening please help!

namespace Defaults {
     constexpr int MOTORS_STANDBY_TORQUE = 200;
     constexpr int MOTORS_OVERLOAD_PERIOD = 100;
     constexpr int MOTORS_STANDBY_CURRENT = 850;
     constexpr int MOTORS_GRIP_ACCELERATION = 25;
}

void MotorDriver::close_grip_with_hold_current(uint16_t protection_current) {

    int MOTOR_ID = 1;
    const int release_offset = 5;
    const int max_wait_ms = 4000; // Maximum wait time for closing (adjust as needed)
    const int position_tolerance = 5; // Acceptable error in position
    const int unchanged_cycles_required = 3; // Require position unchanged for 3 cycles
    const int position_stall_threshold = 2; // Threshold for considering position unchanged
    // unlock eeprom to allow writing protection settings
    sms_sts.unLockEprom(MOTOR_ID);
    sms_sts.SetProtectionCurrent(MOTOR_ID, protection_current);
    sms_sts.SetOvercurrentProtectionTime(MOTOR_ID,    Defaults::MOTORS_OVERLOAD_PERIOD/10); // sms_sts expects time in 10ms units
    // lock eeprom to prevent accidental writes
    sms_sts.LockEprom(MOTOR_ID); 
    sms_sts.WritePosEx(MOTOR_ID, pGlobalConfig->close_position, pGlobalConfig->speed, Defaults::MOTORS_GRIP_ACCELERATION); 
    vTaskDelay(50 / portTICK_PERIOD_MS);
    int elapsed = 0;
    int last_pos = -1;
    int unchanged_cycles = 0;
    while (elapsed < max_wait_ms) {
      vTaskDelay(30 / portTICK_PERIOD_MS);
      elapsed += 30;
      int moving = sms_sts.ReadMove(MOTOR_ID);
      int pos = sms_sts.ReadPos(MOTOR_ID);
      int load = sms_sts.ReadLoad(MOTOR_ID);
      if (!moving) break;

      if (abs(pos - last_pos) <= position_stall_threshold) {
        unchanged_cycles++;
        if (unchanged_cycles >= unchanged_cycles_required) break;
      } else {
        unchanged_cycles = 0;
      }
      last_pos = pos;
    }
    vTaskDelay(100 / portTICK_PERIOD_MS);
    int final_pos = sms_sts.ReadPos(MOTOR_ID);
    int final_load = sms_sts.ReadLoad(MOTOR_ID);
    if (abs(pGlobalConfig->close_position - final_pos) > position_tolerance) { // Not reached, obstacle detected
      sms_sts.WritePosEx(MOTOR_ID, final_pos-release_offset, pGlobalConfig->speed, Defaults::MOTORS_GRIP_ACCELERATION); // loose grip a bit and hold
    }
    sms_sts.unLockEprom(MOTOR_ID);
    sms_sts.SetProtectionCurrent(MOTOR_ID, Defaults::MOTORS_STANDBY_CURRENT); // Reduce current to standby value
    sms_sts.LockEprom(MOTOR_ID);
    sms_sts.WritePosEx(MOTOR_ID, final_pos-release_offset, pGlobalConfig->speed, Defaults::MOTORS_GRIP_ACCELERATION);
    elapsed = 0;
}

void MotorsDriver::open_grip() {
  sms_sts.SetOverloadTorque(MOTOR_ID, Defaults::MOTORS_STANDBY_TORQUE);
  sms_sts.WritePosEx(MOTOR_ID, m_conf->open_position, m_conf->speed, Defaults::MOTORS_GRIP_ACCELERATION);

}

Hi, @tornado67
Welcome to the forum.

Can you post link to data/specs, manual of the servo?
There should be a way of reading any error code from the LED or the comms link.

I assume it is a servo and controller in one housing.

Tom.... :smiley: :+1: :coffee: :australia:

1 Like

Hi Tom! Thanks for your reply.

Here is the only manuals I was able to find

https://www.waveshare.com/w/upload/f/f4/ST3215_Servo_User_Manual.pdf#page18

The thing is that all the functions in their library return an error code or 0 on success and in my code they all keep returning 0 and pretending that everything is okay. The library does not provide anything to read alerts or errors and their manual didn’t seem helpful to me… I used some ChatGPT to generate diagnostics/alert reading and “unbricking” code but that was unhelpful as well.

Those extra blank lines between code lines is NOT helpful. Will look at code only after you remove and do an Auto Format.

Sorry, this is how it pasted, cleaned it up. Any help would be appreciated.

A simple google of STS3215 returns the following

ST3215 Servo User Manual

It appears that some of the code at least is missing. Nobody can help if the code is incomplete.

I saw the manual you sent me and it was not helpful and if you would pay a little more attention you would have seen that I have attached the same manual to my second message. Here is the initialization code. The rest is already provided.

void MotorDriver::begin(){
    pinMode(2, OUTPUT); 
    digitalWrite(2, HIGH); // board's specific, enables servo's power.
    m_log = Logger::getInstance();
    pGlobalConfig= GlobalConfig::getInstance();
    Serial1.begin(1000000, SERIAL_8N1, S_RXD, S_TXD);
    sms_sts.pSerial = &Serial1;
    delay(1000);
    int ID = sms_sts.Ping(MOTOR_ID);
    if (ID == -1){
        return;
    }
    pos = sms_sts.ReadPos(MOTOR_ID);
}

My apologies, I did indeed miss your link to the manual.

I see you are a first-time poster and that @TomGeorge in post 2 advised you what to read as a first timer. Once we see ALL the code and a wiring diagram someone may be able to help.