2016-11-23 35 views
0

我有一個應用程序,其中我需要:使用Arduino的到一個位置,並在該位置 同步使用串行通信

  • 停止

    1. 移動的伺服電動機具有攝像機通過蟒獲取控制在該位置
    2. 當圖像被獲取的圖像,伺服應該移動到的序列被重複的時間N個對稱位置

    所以我試圖使用串行通信來同步arduino和python代碼。在arduino方面,當伺服器到達一個位置時,它使用串行通信向python代碼發送一個字符串。該字符串是「Cross」或「Co」,具體取決於到達的位置。 arduino應該等待串行通信通過python代碼發送字符串「Ok」(圖像採集後)。收到這個字符串後,arduino應該啓動伺服器,使其移動到另一個位置。

    在Python代碼側,我讀串行數據,並根據所述字符串接收(交叉或Co):

    1. 字符串名稱被定義
    2. 的圖像被使用相機
    3. 獲取圖像被保存或追加到列表中
    4. 字符串「Ok」被髮送到arduino。

    該代碼附在下面。

    問題是我無法正確同步伺服位置和圖像採集。伺服只是在兩個位置之間來回運行,似乎沒有從串行通訊中讀取任何字符串。然後它永遠不會真正停止到某個位置。然而,arduino代碼確實向Python代碼發送了「Cross」和「Co」,並且python代碼設法讀取它們並獲取並保存圖像,但通常使用錯誤的名稱。讓arduino代碼在每個位置等待足夠長的時間並不是一個解決方案,因爲我需要一個體面的圖像採集頻率。
    所以我想知道什麼是同步兩個代碼的最佳方法,並確保我的圖像的正確名稱將對應於伺服器的正確位置?

    在此先感謝您的任何鏈接或想法。

    格雷格

    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

    Arduino是否發送收到的'Ok'? –

    +0

    只有當緩衝區中有單個字節時,Serial.available()<2'纔會成立。 'Ok \ n'是三個字節。你永遠不會通過閱讀清除緩衝區。 –

    +0

    是的,我希望代碼在while循環中等待,而只有2個字節,並且在有三個時(如「Ok \ n」)。當你說清除緩衝區時,你的意思是沖洗它嗎? – gregory

    回答

    0

    在你loop()功能,你已經實現了你的軟件作爲功能將被作爲main()執行一次在控制檯軟件中。

    由於的Arduino(C langage)具有通過與計算機(Python的langage)串行鏈路通信,一個有效的解決方案是使用狀態機原理。

    步驟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 - 定義開始參數

    存儲持久數據betwee ñ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行動 「OK」確認。

    (可選)添加比較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; 
        } 
    } 
    
    +0

    好的,謝謝。它就是它。 – gregory