0

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 = 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.

1
  • 1
    Serial.print() is slow - try a faster baud rate, like 115200?
    – Nick Gammon
    Jul 31 '15 at 5:20
0

Mr Gammon's comment about using a faster baud rate is an excellent idea.

You also seem to be sending the number as a string. Sending the integer as binary data (using python's struct module) would also reduce the amount of data that needs to be sent - significantly for larger numbers.

import struct

...

ser.write(struct.pack('I',int(avg)))

On the Arduino Side

uint8_t buffer[4];
uint32_t position;

if (my_serial.read(buffer, sizeof(uint32_t)) == sizeof(uint32_t))
    memcpy(&position, buffer, sizeof(uint32_t));

// alternatively in one step, without error checking
my_serial.read(&position, sizeof(uint32_t));

This assumes a 32-bit integer is needed.
Maybe you only need an unsigned short - this would halve the amount needed to transmit.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.