OpenCV: something wrong with my data xfer into Arduino

The data getting to the Arduino from the script is apparently in a format I'm not expecting. I've tested manually with the Arduino.serial interface, sending various values.

As you can see below, the Arduino code runs down to the panval code once, displaying the -1 from the Serial.read, as it will everytime, unless I send a manually entered value. So I assume the -1 is merely a representation of no input at te Serial.read. The next cycle I passed a '200300' to it, and this time the Serial.read itself had a 48 in it (0?), however, the 'reading' variable loaded from the Serial.read is still a -1. ..huh?

I feel like I'm missing something ...

I've pasted the Arduino Serial.prints, the complete Arduino code and the script.

Arduino.serial

Start
In while loop Reading:-1<
In pan loop Reading: -1
Serial.read: -1
panval: 90

(second cycle)
In while loop Reading:-1<
In pan loop Reading: -1
Serial.read: 48
panval: 90
At fix limits
 

Arduino code

#include <Servo.h>

Servo pan;  // create servo object to control a servo
Servo tilt;

int tiltval = 90;    
int panval = 90;
int positionval = 50;
int reading;
const int DeltaX = 2;     // This is essentially how fast your mount will move in the x direction
const int DeltaY = 1;

const int panMin = 5;
const int panMax = 175;
const int tiltMin = 5;
const int tiltMax = 175;
const int Tolerance = 5;          // How far from the center is still considered OK

void setup()
{
  Serial.begin(115200);
  Serial.write(42);
  pan.attach(9);  // attaches the servo on pin 9 to the servo object
  tilt.attach(10);
}

void loop()
{

Serial.println("Start");
  while (!Serial.available())
  {
    reading = Serial.read();
    Serial.print("In while loop Reading:");
    Serial.print(reading);
    Serial.println("<");
    if( reading != 250)  <====== set this to not equal to get into the pan loop
    {
      Serial.print("In pan loop Reading: ");
      Serial.println(reading);
      Serial.print("Serial.read: ");
      Serial.println(Serial.read());
      while(!Serial.available()) ;                                                    // Wait for position val
      positionval = Serial.read();                                                    // Get the position value for pan

      if ( positionval > (50 + Tolerance))                                           // If the change is greater that 2 degrees
      {       
          panval = panval - DeltaX;                                                   // Add delta to panval
      }
      if ( positionval < (50 - Tolerance))
      {
        panval = panval + DeltaX;
      }
      Serial.print("panval: ");
      Serial.println(panval);
      }

    if( reading == 251) // tilt code
    {
      Serial.println("In tilt loop");
      while(!Serial.available()) ;
      positionval = Serial.read();                                               // Get the position value for tilt
       if ( positionval > (50 + Tolerance) )                                     // If the change is greater that 2 degrees
      {       
          tiltval = tiltval + DeltaY;                                            // Add delta to tiltval
      }
      if ( positionval < (50 - Tolerance))
      {
        tiltval = tiltval - DeltaY;
      }
    }
  }
 
  Serial.println("At fix limits");
  FixLimits();      // Fix limits to avoid overdriving servos

  // Write the angle to

  tilt.write(tiltval);
  pan.write(panval);                  // sets the servo position according to the scaled value
  delay(1000);                           // waits for the servo to get there
}

void FixLimits()
{
  if (tiltval > tiltMax) tiltval = tiltMax;
  if (tiltval < tiltMin) tiltval = tiltMin;
  if (panval > panMax) panval = panMax;
  if (panval < panMin) panval = panMin;
}

 

Script
 
 # create or get a handle to an OpenCV
opencv = Runtime.createAndStart("opencv","OpenCV")
# Convert the video to Black and White
opencv.addFilter("Gray1", "Gray")                             
# Sometimes gray seems to help# reduce the size - face tracking doesn't need much detail. The smaller the
opencv.addFilter("PyramidDown1", "PyramidDown")
# add the face detect
opencv.addFilter("FaceDetect1", "FaceDetect")
opencv.capture()

#create a Serial service named serial
serial = Runtime.createAndStart("serial","Serial")

# This function is called every time the OpenCV service has data available.
# This will depend on the framerate of the video, but will probably be
# somewhere around 15 times a second.
def input():
    global x
    global y
    global sposx
    global sposy
    global posx
    global posy

    # Get OpenCV data
    opencvData = msg_opencv_publishOpenCVData.data[0]

    if (opencvData.getBoundingBoxArray().size() > 0) :    # If the box surrounding a face exists
     rect = opencvData.getBoundingBoxArray().get(0)       # Store the information in rect
     posx = rect.x                                        # Get the x position of the corner
     posy = rect.y                                        # Get the y position of the corner
 
     w = rect.width                                       # Get the width
     h = rect.height                                      # Get the height
     sposx = (w/2)
     sposy = (h/2)
     # Get the x and y of the center in pixels. Origin is in top left corner
     x = (posx + sposx)  
     y = (posy + sposy)
     
     # Convert x,y pixels to (x,y) coordinates from top left.
     # Note that 320 and 240 will need to be changed if another pyramid down is used
     # It may also need to be changed depending on your cameras specifications.
     # This gets the position in a scale from 1, 100
     x = int(translate(x, 1, 320, 1, 100));                  # translate() works the same way the Arduino map() function would
     y = int(translate(y, 1, 140, 1, 100));
     print 'x: ' ,  x                                        # print x to the python readout
     print 'y: ' ,  y                                        # print y to the python readout
     #write a series of bytes to the serial port
     serial.write(250) # pan code
     serial.write(x)   # x coordinate
     serial.write(251) # tilt code
     serial.write(y)   # y coordinate

serial.connect("COM3", 115200, 8, 1, 0)
#sometimes its important to wait a little for hardware to get ready
sleep(1)          # Note that this is 1 full second.

# create a message route from opencv to python so we can see the coordinate locations
opencv.addListener("publishOpenCVData", python.name, "input");

# Start capturing video
opencv.capture()  # Add a 1 inside the parenthesis to use camera 1

# Create function to scale values. Mimics Arduino map() function.
def translate(value, leftMin, leftMax, rightMin, rightMax):
    # Figure out how 'wide' each range is
    leftSpan = leftMax - leftMin
    rightSpan = rightMax - rightMin

    # Convert the left range into a 0-1 range (float)
    valueScaled = float(value - leftMin) / float(leftSpan)

    # Convert the 0-1 range into a value in the right range.
    return rightMin + (valueScaled * rightSpan)

sleep(1)
 

Mats's picture

Services in MRL

Hi

You can make it much easier for yourself if you use the Servo and Arduino services in MRL. Then you don't have to write your own sketch in the Arduino.

MRL contains a sketch called MRLComm. It works together with the Arduino service. So you install the MRLComm sketch using the Arduino IDE. You can follow this guide:

http://www.myrobotlab.org/content/uploading-mrlcomm-arduino-0

Then you can use the Servo service to control the servos. One Servo service for each servo.

This is how you can find what methods that are available in each service:

http://myrobotlab.org/content/dynamic-documentation-all-methods-mrl-vali...

And each service ( most of them ) also has a documentation page that you can reach from the runtime tab. Rightclick and select Info. This is the documentation page for the Servo service:

http://myrobotlab.org/service/Servo 

/Mats