Pyserial and Accelstepper

I am trying to send an integer value from Python to Arduino. The integer value is a position given by a webcam, which will determine how many turns a stepper motor moves.

Arduino:

#include <AccelStepper.h>
AccelStepper stepper(AccelStepper::DRIVER,8,9); 

void setup() {
  Serial.begin(9600);
  stepper.setMaxSpeed(1000.0);
  stepper.setAcceleration(700.0);
}

void loop() {
  int val = 0;
  if(Serial.available()){
    //val = Serial.parseInt();
    //Serial.println(val);
    if (Serial.parseInt()>=0 && Serial.parseInt()<=1280){
      val = map(Serial.parseInt(), 0, 1280, 0, 551); 
      Serial.println(val);
    }
  }
  stepper.runToNewPosition(val);  
}

Python:

# source: http://www.steinm.com/blog/motion-detection-webcam-python-opencv-differential-images/

import cv2
import numpy as np
import serial
import time

def diffImg(t0, t1, t2):
    d1 = cv2.absdiff(t2, t1)
    d2 = cv2.absdiff(t1, t0)
    dif = cv2.bitwise_and(d1, d2)
    return np.fliplr(dif)

cam = cv2.VideoCapture(0)  

#winName = "Movement Indicator" #camera window
#cv2.namedWindow(winName, cv2.WINDOW_NORMAL)

# Read three images first:
t_minus = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
t = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
t_plus = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)

h, w = t.shape

winTest = "Test Window" #test window
cv2.namedWindow(winTest, cv2.WINDOW_NORMAL)

thresh = 100

ser=serial.Serial('/dev/cu.usbmodem1411',9600,timeout=0)
time.sleep(2)

while True:
    
    img = diffImg(t_minus, t, t_plus)

#    cv2.imshow(winName, img )

    nz = np.transpose(np.nonzero(img>thresh))
    a = 0
    b = 0
    c = 0
    d = 0
    avg=0
    if nz.size>0:
        a,b = nz[0]
        c,d = nz[-1]
        avg = (b+d)/2
        if 0<=avg and avg<=1280:
            print avg
            ser.write(str(int(avg))+" ") 

    test = np.zeros((h,w))

    cv2.rectangle(test, ((avg-5),a), ((avg+5),c), (255), -1)
    cv2.imshow(winTest, test )

    # Read next image
    t_minus = t
    t = t_plus
    t_plus = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
    print ser.readline();   
    

    key = cv2.waitKey(10)
    if key == 27:
       cv2.destroyWindow(winName)
       ser.close()
       break

print "Goodbye"

This works OK but occasionally ‘val’ will take some ridiculous value, say 7182, and the motor spins out of control. I realize I can check values with an if statement before I actually write to the stepper motor, but I think my problem is with reading and writing to the Arduino.

My other issue is I feel Arduino is not receiving some of the data sent to it via serial connection. This is hard to say, as Serial.print() is slow and mostly doesn’t make it through to my terminal before it’s already been rewritten.

Have a look at the examples in serial input basics. They are simple, reliable and non-blocking. Serial.parseInt() is a blocking function. The 3rd example will be most reliable.

You may also be interested in this Python - Arduino demo.

I can't immediately see from your Python code but it is essential that it keeps the serial port open until it is completely finished with the Arduino.

...R

    if (Serial.parseInt()>=0 && Serial.parseInt()<=1280){
      val = map(Serial.parseInt(), 0, 1280, 0, 551); 
      Serial.println(val);

If the first integer is greater than or equal to zero, and the second is less than or equal to 1280, map the third one to a range and move the servo. You’ll need to explain THAT logic to me.