I have an application where I need to:
- move a servo motor using arduino to a position and stop at that position
- have a camera controlled by python acquire an image at that position
- when the image is acquired, the servo should move to a symmetrical position
The sequence is repeated a number N of time
So I tried to synchronize the arduino and the python code using serial communication. On the arduino side, when the servo reaches a position, it sends a string to the python code using serial communication. The string is either "Cross", or "Co" depending of the position reached. The arduino should wait for a string "Ok" to be sent by serial communication by the python code (after image acquisition). After receiving this string, the arduino should actuate the servo for it to move to the other position.
On the python code side, I read serial data and depending on the string received (Cross or Co):
- a string name is defined
- An image is acquired using the camera
- the image is saved or append to a list
- The string "Ok" is sent to arduino.
the codes are attached below.
The problem is that I do not manage to synchronize correctly the servo positions and the image acquisition. The servo just run back and forth between the two positions and does not seem to be reading any string from the serial communication. It then never stops really to a position. The arduino code however does send "Cross" and "Co" to the python code, and the python code does manage to read them and acquire and save images but often with the wrong names. Having the arduino code waits long enough at each position is not a solution, since I need a decent frequency of image acquisition.
So I would like to know what is the best way to synchronize the two codes and be sure, that the right name of my images will correspond to the right position of the servo?
Thanks in advance for any link or ideas.
Greg
arduino code `
#include <Servo.h>
//servo
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
//camera
const int CameraPin = 53; // the number of the camera trigg
int CameraState = LOW; // ledState used to set the LED
const int ledPin = 13; // the number of the LED pin
String Str = "c";
void setup() {
myservo.attach(9); // attaches the servo on pin 9 to the servo object
// set the digital LED pin as output:
pinMode(CameraPin, OUTPUT);
// set the digital camera pin as output:
pinMode(ledPin, OUTPUT);
//serial communication
Serial.begin(9600);
Serial.println("Ready");
}
void loop() {
Serial.flush();
// go to Co position and wait
ServoCo(15); // go to Co position
Serial.println("Co"); //send signal Co to python
while(!Serial.available()) {} // wait for python to send data acquired
while ((Serial.available()<2)) // Test on the length of the serial string
{
delay(1);
String Str = Serial.readStringUntil('\n');
Serial.println(Str);
}
// go to cross position and wait
ServoCross(15); // go to Cross position
Serial.println("Cross");
while(!Serial.available()) {}
while ((Serial.available()<2))
{
delay(1);
String Str = Serial.readStringUntil('\n');
Serial.println(Str);
}
}
delay(100);
}
void ServoCross(int ServoDelay)
{
for (pos = 105; pos >= 75; pos -= 1) { // goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(ServoDelay);
}
}
void ServoCo(int ServoDelay)
{
for (pos = 75; pos <= 105; pos += 1)
{ // goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(ServoDelay);
}`
Python code:
from time import sleep
import serial
import scipy
ser = serial.Serial('COM10', 9600) # Establish the connection on a specific port
Nb_total_image = 100
imagergb_cross = np.zeros((480,640))
imagergb_co = np.zeros((480,640))
counter_image = 0;
ser.write('start')
while counter_image<Nb_total_image:
ser.flush()
ReadArduino = ser.readline().split('\r')[0] # Read the newest output from the Arduino
print(ReadArduino)
if ReadArduino == 'Cross':
nameImage = 'CrossImage' + str(counterImageCross)
cam.reset_frame_ready() # reset frame ready flag
# send hardware trigger OR call cam.send_trigger() here
cam.send_trigger()
cam.wait_til_frame_ready(1000) # wait for frame ready due to trigger
imageRawcross = cam.get_image_data()
ser.write("Ok\n")
else:
nameImage = 'CoImage' + str(counterImageCo)
cam.reset_frame_ready() # reset frame ready flag
# send hardware trigger OR call cam.send_trigger() here
cam.send_trigger()
cam.wait_til_frame_ready(1000) # wait for frame ready due to trigger
ImageRawCo = cam.get_image_data()
ser.write("Ok\n")
imagergb = imageRawCo-imageRawcross
counter_image = counter_image + 1
Okback?Serial.available()<2will only be true, when there is a single byte in the buffer.Ok\nis three bytes. And you never clear the buffer by reading it.loop()function doesn't comply with a periodical call of that function. Note: it seems that the count of open-brackets is not equal to the close-brackets in that function.ServoCo()the last close-bracket is missing.