Good day, I'm trying to control a servo motor by feeding it dynamic values, Im sending the dynamic values through serial port form a python code, but whenever I try to run the python code the motor would go to 180 degrees and start jerking then it stops responds
but when I feed it Static values it responds fine, what could be the problem when it comes to the dynamic values? Thank you
#include <Servo.h>
Servo servoA; // Create a servo object for motor A
int motorA_pin = 13; // Define the pin for motor A
void setup() {
Serial.begin(2000000); // Initialize serial communication at 9600 baud
servoA.attach(motorA_pin); // Attach servoA to pin 10
servoA.write(90); // Set initial position for motor A
}
void loop() {
if (Serial.available() > 0) {
String data = Serial.readStringUntil('\n'); // Read the data until newline character
int motorValue = data.toInt(); // Convert the received string to an integer
if (motorValue >= 0 && motorValue <= 180) { // Ensure the received value is within servo's range
servoA.write(motorValue);
}
while (Serial.available() > 0) {
Serial.read();
}
}
}
and sending the dynamic values using : `arduino.write(f"{motorA1}\n".encode())`
I tried but I cant view the Serial monitor since the comport is being used by python to send the values to Arduino
Oh I havent tried using the Serial.parseInt(), Do i have to change the way im sending the data to arduino for the Serial.parseInt() to work or it is still fine as a string?
IDK what you mean the difference between static and dynamic to be.
If you are sending values out at a higher rate than typing them in one at a time (wherever), then this
while (Serial.available() > 0) {
Serial.read();
}
the purpose of which is a mystery to me, may be an issue.
So… why you do that?
And… what means dynamic vs. static?
BTW, the receiving entity has no idea what the sender did to create the characters it transmits. It is on the Arduino board that we might prefer to void Strings; here that is easily done as you see.
Not knowing how "dynamic" your values are, Have you considered the delays in communicating from the Python to the Arduino to the driver?
Do you have a feeling what the dynamic values should be? You could use a case statement switching on/off a number of LEDs on different output pins to get a feeling of what numbers are being passed through.
Adding delays would make the system respond slow, in this scenario I'm sending motor commands (servo angles ) to the Arduino depending on the position of the ball I'm tracking using a camera, so the numbers I'm sending to the Arduino are desired motor angles to balance the ball in the canter
In a properly designed system of one machine telling another what to do over serial comms there is no need, and in fact it is a bad idea, to clear the buffer. Ever.
You aren't using to Arduino to power the servo, are you? Arduino connection to a servo should ideally be signal and ground only.
Also, Hitec Servos can be finicky. The servo library sets servo position one of two ways: by angle, as you've done or with writeMicroseconds() where the argument is typically between about 1000-2000 microseconds, 1000 corresponding to about 0 degrees, 1500 to 90 degrees, 2000 to 180 degrees.
Hitec has some digital servos where the servo only responds to a limited range, something like 1500-2000 or so. I have had Hitec ones whose range was 600-2400 uS. Maybe try using
servoA.writeMicroseconds(1500);
instead of
servoA.write(90);
to see, or use both and compare. Start with values closer to 1500 first to avoid overdriving the servo and it may take a little trial and error.
Check the servo datasheet too, but if the two lines I just supplied aren't about the same, ie midpoint, then the servo timing is one of those finicky Hitec ones.
@bakanium if you want to stick with angles, you can
servo.attach(pin, min, max);
use a different attach() call and specify in microseconds the values for corresponding to 0 and 180.
Which don't have to be the real angles, either. 0 will go where the minimum pulse would go, and 180 to the maximum.
So you might determine the min and max by experimenting with writing the values in microseconds as outlined by @hallowed31, then place those in the attach call.
Please do not duplicate your questions as doing so wastes the time and effort of the volunteers trying to help you as they are then answering the same thing in different places.
Please create one topic only for your question and choose the forum category carefully. If you have multiple questions about the same project then please ask your questions in the one topic as the answers to one question provide useful context for the others, and also you won’t have to keep explaining your project repeatedly.
Repeated duplicate posting could result in a temporary or permanent ban from the forum.
Could you take a few moments to Learn How To Use The Forum
It will help you get the best out of the forum in the future.
Try this test program to learn what your servo does with different inputs.
Connect servo signal wire to pin 9, set serial monitor line ending to "Newline".
/*
Try this test sketch with the Servo library to see how your
servo responds to different settings, type a position
(0 to 180) or if you type a number greater than 180 it will be
interpreted as microseconds(544 to 2400), in the top of serial
monitor and hit [ENTER], start at 90 (or 1472) and work your
way toward zero (544) 5 degrees (or 50 micros) at a time, then
toward 180 (2400).
*/
#include <Servo.h>
Servo servo;
void setup() {
// initialize serial:
Serial.begin(9600); // set serial monitor baud rate to match
// set serial monitor line ending to "NewLine"
servo.write(90);
servo.attach(9);
prntIt();
}
void loop() {
// if there's any serial available, read it:
while (Serial.available() > 0) {
// look for the next valid integer in the incoming serial stream:
int pos = Serial.parseInt();
if(Serial.read() == '\n'){} //skip 1 second delay
pos = constrain(pos, 0, 2400);
servo.write(pos);
prntIt();
}
}
void prntIt()
{
Serial.print(" degrees = ");
Serial.print(servo.read());
Serial.print("\t");
Serial.print("microseconds = ");
Serial.println(servo.readMicroseconds());
}
I think you're constraining to the lower end of servo.write(0); as in degrees, and the upper end of servo.writeMicroseconds(2400); which would, in some servos, correspond to servo.write(180);
Or am I missing something? Does the library auto convert values over 180 as the alternate write method?
void Servo::write(int value)
{
if (value < MIN_PULSE_WIDTH)
{ // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
if (value < 0) value = 0;
if (value > 180) value = 180;
value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
}
this->writeMicroseconds(value);
}
void Servo::writeMicroseconds(int value)
{
// calculate and store the values for the given channel
byte channel = this->servoIndex;
if ((channel < MAX_SERVOS)) // ensure channel is valid
{
if (value < SERVO_MIN()) // ensure pulse width is valid
value = SERVO_MIN();
else if (value > SERVO_MAX())
value = SERVO_MAX();
value = value - TRIM_DURATION;
value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009
uint8_t oldSREG = SREG;
cli();
servos[channel].ticks = value;
SREG = oldSREG;
}
}