Improving response time of Servo over Serial and streaming a series of Positions

So basically there’s some slight drift in my robot that I’ll be detecting using an IMU that I would like to correct by telling the servos to compensate.

However, I’ve been working using pyserial and a basic arduino servo library, but there’s a roughly second delay between my entering the python command and the servo actually moving. I was wondering if anyone knew where that delay is coming from? Since it’d be a bit much, for what I wanted to do.

Setup is wired to the digital PWM pin 9, 5V, and ground using a Datan S1213 servo. With super basic code:

#include <Servo.h>

Servo myServo;  // create servo object to control a servo
// twelve servo objects can be created on most boards

int pos = 0;    // variable to store the servo position


void setup() {
  myServo.attach(9);
  Serial.begin(115200);
}

void loop() {
  if(Serial.available() > 0)
  {
    int pos=Serial.parseInt();
//    Serial.print(angulo);
    myServo.write(pos);
  }
}

import serial
ser = serial.Serial('/dev/cu.usbmodem1411', 115200) # Establish the connection on a specific port
def servoGoTo(pos):
    ser.write(str(pos))

And as a separate issue that’s really bizarre. When I step through the position below using this for loop, as long as the time.sleep is 1 or greater, it works. However, if I use time.sleep(0.99) the servo freezes there. However, if I manually call the servoGoto(0) and immediately (less than one second) call servoGoto(180), I can flip back and forth. It just queues them up to some degree. I don’t expect it to queue commands, but I need to be able to send commands faster than 1 per second, to make small movements in small amounts of time to get better movement resolution.

for i in range(0,180, 45):
    servoGoTo(i)
    time.sleep(1)

If I needed to I could probably write some compensation software into the arduino code, but the weird issue where I can’t send commands less than 1 second really hampers things. They might be related issues, but any help is super appreciated! I’ve looked through several dozen threads and multiple search terms and still haven’t been able to find any leads.

Hi, Can you post the entire code please?

Thanks.. Tom.. :)

There should be no noticeable delay. My guess is that Serial.parseInt() is the culprit.

Have a look at the examples in Serial Input Basics - simple reliable non-blocking ways to receive data. There is also a parse example to convert the received data to an int.

...R

Are there no other sleep calls in Python?

I'd try to send an acknowledgement from the Arduino, and let the code wait for it.

AH!!! The two issues were related and Robin2 you were right about the parseInt(). It must have a wait to see if it’s done receiving since it doesn’t require a data termination code. Time sleeps 0.1 or whatever work fine now.

Here’s the full code for the greater good of the world. It’ll allow nearly instantaneous control of your servo:

//Arduino Code

#include <Servo.h>

Servo myServo;  // create servo object to control a servo
int pos = 90;    // variable to store the servo position
String inString = "";    // string to hold input

void setup() {
  myServo.attach(9);
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // send an intro:
  Serial.println("\n\nString toInt():");
  Serial.println();
}

void loop() {
  // Read serial input:
  while (Serial.available() > 0) {
    int inChar = Serial.read();
    if (isDigit(inChar)) {
      // convert the incoming byte to a char
      // and add it to the string:
      inString += (char)inChar;
    }
    // if you get a newline, print the string,
    // then the string's value:
    if (inChar == '\n') {
      Serial.print("Value:");
      Serial.println(inString.toInt());
      Serial.print("String: ");
      Serial.println(inString);

      myServo.write(inString.toInt());
      // clear the string for new input:
      inString = "";
    }
  }
}

# Python Code
import time
import serial
ser = serial.Serial('/dev/cu.usbmodem1411', 115200) # Establish the connection on a specific port

def servoGoTo(pos):
    outputStr = str(pos)+'\n'
    print(outputStr)
    ser.write(outputStr)

servoGoTo(90)

Many Thanks to Everyone who chimed in, I really appreciate everyone reaching out to help me solve these mysteries… lol :smiley: