我有一个应用程序,我需要:
序列重复N次
所以我尝试使用串行通信同步arduino和python代码。在arduino方面,当伺服到达某个位置时,它会使用串行通信将字符串发送到python代码。字符串是“交叉”或“Co”,具体取决于到达的位置。 arduino应该等待字符串“Ok”通过python代码通过串行通信发送(在图像获取之后)。收到此字符串后,arduino应启动伺服器,使其移动到另一个位置。
在python代码方面,我读取串行数据并根据收到的字符串(Cross或Co):
下面附有代码。
问题在于我无法正确同步伺服位置和图像采集。伺服只是在两个位置之间来回运行,似乎没有从串行通信中读取任何字符串。然后它永远不会停止到一个位置。然而,arduino代码确实将“Cross”和“Co”发送到python代码,并且python代码确实设法读取它们并获取和保存图像,但通常使用错误的名称。让arduino代码在每个位置等待足够长的时间不是解决方案,因为我需要一个合适的图像采集频率 所以我想知道同步两个代码的最佳方法是什么,并确保我的图像的正确名称对应于伺服的正确位置?
提前感谢任何链接或想法。
Greg
arduino代码 `
#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代码:
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
答案 0 :(得分:3)
在loop()
功能中,您已实施了软件,因为该功能将在控制台软件中以main()
执行一次。
因为 Arduino (C语言)必须通过串行链接与您的计算机进行通信(Python语言),所以一种有效的解决方案是使用状态机原则。 / p>
第1步 - 定义所需的州名列表以及要达到的职位数。
一个简单的
enum e_State
允许定义列表。
typedef enum e_State {
STATE_START = 0, // first state to initialize
STATE_MOVE_POS, // moving Servo to the selected position
STATE_SEND_CMD, // sending message when position reached
STATE_WAIT_ACK // waiting acknowledge from message
} eState;
对于要达到的2个职位,使用
enum e_Pos
:
typedef enum e_Pos {
FIRST_POS = 0,
SECOND_POS
} ePos;
第2步 - 定义起始参数
在
loop()
个调用static
个变量之间存储持久数据 使用:
static eState LoopState = STATE_START; // to store the current state
static ePos ServoPos = FIRST_POS; // to store the selected position
要暂时存储下一个状态,请添加eState NextState
。
loop()
函数的输入,NextState = LoopState;
到 默认情况下保持相同的状态。
第3步 - 定义状态机算法。
void loop() {
static eState LoopState = STATE_START; // to store the current state
static ePos ServoPos = FIRST_POS; // to store the selected position
eState NextState = LoopState;
switch (LoopState) {
case STATE_START:
ServoPos = FIRST_POS;
NextState = STATE_MOVE_POS;
break;
case STATE_MOVE_POS:
NextState = STATE_SEND_CMD;
break;
case STATE_SEND_CMD:
NextState = STATE_WAIT_ACK;
break;
case STATE_WAIT_ACK:
// NextState = STATE_MOVE_POS;
break;
default:
// when undefined state, restart
NextState = STATE_START;
}
// define the state for the next loop
LoopState = NextState;
}
第4步 - 使用选定的STATE_MOVE_POS
管理ServoPos
的操作。
switch (ServoPos) {
case FIRST_POS:
ServoCo(15); // go to 'Co' position
break;
case SECOND_POS:
ServoCross(15); // go to 'Cross' position
break;
};
NextState = STATE_SEND_CMD; // when reached, send serial message
第5步 - 根据到达的STATE_SEND_CMD
管理ServoPos
的操作。
Serial.flush(); // clear the serial buffer
if (ServoPos == FIRST_POS) {
Serial.println("Co"); //send signal 'Co' to python
}
else {
Serial.println("Cross"); //send signal 'Cross' to python
}
NextState = STATE_WAIT_ACK;
第6步 - 通过查找“确定”确认来管理STATE_WAIT_ACK
的操作。
或者,添加比较
if (Str == "OK")
以确保这一点 电脑答案正确。
if (Serial.available()) { // no state change while no acknowledge
String Str = Serial.readStringUntil('\n');
Serial.println(Str);
if (Str == "OK") {
// ack is OK, select the next position and continue
ServoPos = (ServoPos == FIRST_POS)?(SECOND_POS):(FIRST_POS);
NextState = STATE_MOVE_POS;
}
else {
// ack is KO, restart from first position
NextState = STATE_START;
}
}