Extracting text from QR Codes

Hello there,

Can anyone help me with my simple project? I’m very new on the OpenMV M7. I just need to move a mini servo depending on the text read on the QR Code.

I’ve used the sample QR Code and the text on the QR is printed on the “payload”. How can i extract the payload and use it as a variable to move the servo by a certain degrees?

import sensor, image, time
from pyb import Servo

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False) # must turn this off to prevent image washout...
clock = time.clock()

while(True):
    clock.tick()
    img = sensor.snapshot()
    img.lens_corr(1.8) # strength of 1.8 is good for the 2.8mm lens.
    for code in img.find_qrcodes():
        img.draw_rectangle(code.rect(), color = (255, 0, 0))
        print(code)
    if (code == "LEFT"): 
    	s1 = pyb.Servo(1)
        s1.angle(45)

I’m pretty sure that the last if statement doesn’t work. How do I proceed with this? Your help is greatly appreciated.

Do:

codes = img.find_qrcodes()
for code in codes:
        img.draw_rectangle(code.rect(), color = (255, 0, 0))
        print(code)
if codes:
    if code[0].payload == "LEFT":
        s1 = pyb.Servo(1)
        s1.angle(45)

This extracts the text for the first QR code seen.

The find QR codes method returns a list of objects, so, I put the list in a variable above, then look at the first object in the list and get the payload of it. I check to make sure the list is not empty first however.

Thanks for the help but I’ve come up into an error while trying the code you provided me. The error that appeared says "AttributeError: ‘int’ object has no attribute ‘payload’.

Can you help me again? Here’s the full code, and while it displays the error it highlights the line of the code: if code[0].payload == “LEFT”:

import sensor, image, time

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)

clock = time.clock()

while(True):
    clock.tick()
    img = sensor.snapshot()
    img.lens_corr(1.8)
    print(clock.fps())
    codes = img.find_qrcodes()
    for code in codes:
            img.draw_rectangle(code.rect(), color = (255, 0, 0))
            print(code)
    if codes:
        if code[0].payload == "LEFT":
            s1 = pyb.Servo(1)
            s1.angle(45)

Sorry, I meant .payload().

The parens are important.

Thank you very much. I’ve tested it before going, it works as expected. One more thing, I’ve printed some QR codes but the OpenMV Cam doesn’t immediately detect it unless on some certain conditions like when the background is white. Also can I use lists like the ones I’ve seen on online references to read multiple payloads?

like:

my_list = ["LEFT", "RIGHT"]

and replace the if codes with:

if code.payload() == "my_list"

will it not cause errors? I’m not at home currently for the next few days and I wanna know if my idea would be functional. Thanks again!

Qr codes require the background to be white. The scanning algorithm looks for certain attributes about the area around a QR code before decoding them. In particular, you absolutely need to have enough of a white border around the codes or the algorithm ignores the codes.

As for your second question… You’re asking how to compare against a list? This is a python question. Just a tip, if something seems like a core language problem google for it and the answer will be available on stack overflow. Just about anything you need to know about python has an answer out there. Anyway, do this:

if code.payload() in my_list:

Yes, python has a method to do what you want built-in.

Hello Friends

I am pretty new to this camera and have big problems to get this code running.
I am copy your Code and included the Parens but getting always the Error
AttributeError: ‘int’ object has no attribute ‘payload’

I tryed to figure the error out for Hours but its not working

import sensor, image, time

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)

clock = time.clock()

while(True):
    clock.tick()
    img = sensor.snapshot()
    img.lens_corr(1.8)
    print(clock.fps())
    codes = img.find_qrcodes()
    for code in codes:
            img.draw_rectangle(code.rect(), color = (255, 0, 0))
            print(code)
    if codes:
        if code[0].payload() == "LEFT":
            s1 = pyb.Servo(1)
            s1.angle(45)

It’s codes[0] not code[0].

Accessing code[0] makes no sense. That variable isn’t in scope at that time in your code. However, since MP doesn’t garbage cleanup variables quickly you don’t get an error about accessing an out of scope variable… But, you are doing that.

Thanks for this perfect code, It works without any error.

Okay that works thanks but i have another Question i am playing arround a bit and try to figure out how i can acces maybe the second character of the payload i tryied differnt things but always with an error message.
On the internet i read something like this print(a[1])

and i tryed to do that with

if codes[0].payload([1]) == “LEFT”:
but then i get this errormessage

TyperError: function takes 1 positional arguments but 2 were given

What does this mean

codes[0].payload()[1]

Will return 1 character. If you want 4 characters starting from position 1 do:

codes[0].payload()[1:4]

Note that these are general python questions you are asking. If you Google how python strings work you’d be able to solve these more quickly.

The payload method returns a string. It doesn’t take any arguments. The index operation is on the returned string.

I have a weird problem i use my code and hooked everything up to comunicate to an arduino uno. If i use the uart example in openmw it works that it outputs everything to the arduino serial monitor.
Now i have a more complex sketch in arduino were the given numbers read out by openmv make a servo move. But it is now only showing weird characters in the serial monitor if the openmv sends the numbers. Also it looks like that the arduino is also sending stuff to the openmv because i can see text that should be outputed in the arduino serial monitor in the serial monitor from openmv. Could you explane this

Code?

There are the codes.
Sorter.rar (2.11 KB)

You could help me please

Can you post your code on the forums in text format using the code blocks?

(I am keeping track of a lot of this on my phone and I will just review your code via the webpage)

import sensor, image, time, pyb
from pyb import UART

red = pyb.LED(1)
green = pyb.LED(2)
blue = pyb.LED(3)
ir = pyb.LED(4)
uart = UART(3, 19200)


sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.set_framesize(sensor.VGA)
sensor.set_windowing((240, 240)) # look at center 240x240 pixels of the VGA resolution.
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False) # must turn this off to prevent image washout...
#clock = time.clock()


while(True):
    #clock.tick()
    img = sensor.snapshot()
   #print(clock.fps())
    codes = img.find_qrcodes()
    for code in codes:
            img.draw_rectangle(code.rect(), color = (255, 0, 0))
            print(code)
    if codes:
        if codes[0].payload()[1] == "0":
            uart.write(code[4])
            if (uart.any()):
             print(uart.read())
            time.sleep(1000)

        if codes[0].payload()[1] == "0":
            uart.write(code[4])
            if (uart.any()):
             print(uart.read())
            time.sleep(1000)

        if codes[0].payload()[1] == "1":
            uart.write(code[4])
            if (uart.any()):
             print(uart.read())
            time.sleep(1000)

        if codes[0].payload()[1] == "2":
            uart.write(code[4])
            if (uart.any()):
             print(uart.read())
            time.sleep(1000)

        if codes[0].payload()[1] == "3":
            uart.write(code[4])
            if (uart.any()):
             print(uart.read())
            time.sleep(1000)

        if codes[0].payload()[1] == "4":
            uart.write(code[4])
            if (uart.any()):
             print(uart.read())
            time.sleep(1000)

        if codes[0].payload()[1] == "5":
            uart.write(code[4])
            if (uart.any()):
             print(uart.read())
            time.sleep(1000)

        if codes[0].payload()[1] == "6":
            uart.write(code[4])
            if (uart.any()):
             print(uart.read())
            time.sleep(1000)

This is the openmv sketch

// zoomkat 12-13-11 serial servo (2) test
// for writeMicroseconds, use a value like 1500
// for IDE 1.0
// Powering a servo from the arduino usually DOES NOT WORK.
// two servo setup with two servo commands
// send eight character string like 15001500 or 14501550
// use serial monitor to test
#include <AccelStepper.h>
#include <AFMotor.h>
#include <Servo.h>

AF_Stepper motor1(200, 1);

String readString, servo1, servo2;
Servo myservo1;  // create servo object to control a servo
Servo myservo2;
Servo myservo3;

int ir1 = 8;
int ir2 = 10;
int ir3 = 11;

int irstart = 4;// connect the starting ir to these pin


//Declare pin functions on RedBoard
#define stp 2
#define dir 3
//#define MS1 4
//#define MS2 5
//#define EN  6

//Declare variables for functions
char user_input;
int x;
int y;
int state;

void StepForwardDefault()
{
  Serial.println("Moving forward at default step mode.");
  digitalWrite(dir, LOW); //Pull direction pin low to move "forward"
  //  for (x = 0; x < 1000; x++) //Loop the forward stepping enough times for motion to be visible
  for (;;)
  {
    digitalWrite(stp, HIGH); //Trigger one step forward
    delay(1);
    digitalWrite(stp, LOW); //Pull step pin low so it can be triggered again
    delay(1);
  }
}

void StopForwardDefault()
{
  Serial.println("stopping  to read default step mode.");
  digitalWrite(dir, LOW); //Pull direction pin low to move "forward"
  for (x = 0; x < 1000; x++) //Loop the forward stepping enough times for motion to be visible
  {
    digitalWrite(stp, LOW); //Trigger one step forward
    delay(1);
    digitalWrite(stp, LOW); //Pull step pin low so it can be triggered again
    delay(1);
  }
}



AccelStepper stepper;//(forwardstep, backwardstep); // use functions to step Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5

void setup() {
  pinMode(stp, OUTPUT);
  pinMode(dir, OUTPUT);

  pinMode(ir1, INPUT);
  pinMode(ir2, INPUT);
  pinMode(ir3, INPUT);


  Serial.begin(19200);
  myservo1.attach(6);
  myservo2.attach(7);  //the pin for the servo control
  myservo3.attach(9);

  stepper.setMaxSpeed(50);
  stepper.setSpeed(50);


  /*
      myservo1.write(45);
      // delay(30);
      // myservo1.write(0);
      delay(30);


      myservo2.write(45);
      //delay(30);
      //myservo2.write(0);
      delay(30);

      myservo2.write(45);
      //delay(30);
      //myservo1.write(0);
      delay(30);
  */
  digitalWrite(ir1, LOW);
  digitalWrite(ir2, LOW);
  digitalWrite(ir3, LOW);

  Serial.println("SORTING MACHINE");
  Serial.println("CONFIGURINRATON DONE");
}

void loop() {
  int ir1read = digitalRead(ir1);
  int ir2read = digitalRead(ir2);
  int ir3read =  digitalRead(ir3);


  ////================================================


  //=====================================================
  if (Serial.available() > 0) {
    StopForwardDefault();
    mains();
  }
  else {
    StepForwardDefault();
    if (ir1read == HIGH) {
      myservo1.write(45);
      delay(30);
    }
    if (ir2read == HIGH) {
      myservo3.write(45);
      delay(30);
    }
    if (ir3read == HIGH) {
      myservo3.write(45);
      delay(30);
    }
  }
}
void mains()
{
  while (Serial.available()) {
    // StopForwardDefault();
    delay(3);  //delay to allow buffer to fill
    if (Serial.available() > 0) {
      char c = Serial.read();  //gets one byte from serial buffer
      // Serial.println(c);
      readString += c; //makes the string readString
    }
  }
  if (readString.length() > 0) {
    Serial.println(readString); //see what was received

    // expect a string like 07002100 containing the two servo positions
    servo1 = readString;  //.substring(0, 2); //get the first four characters
    // servo2 = readString.substring(4, 8); //get the next four characters
    Serial.println("CONTROL THE SERVO ::  ");
    Serial.print(servo1);  //print to serial monitor to see parsed results
    //   Serial.println(servo2);
    if ( servo1 .startsWith("10")) {
      myservo1.write(180);
      delay(30);
      Serial.println("SERVO 1 MOVED    ");
    }
    else  if ( servo1 .startsWith("11")) {
      myservo2.write(180);
      delay(30);
      Serial.println("SERVO 2 MOVED    ");
    }
    else if ( servo1 .startsWith("12")) {
      myservo3.write(180);
      delay(30);
      Serial.println("SERVO 3 MOVED    ");
    }

    readString = "";

  }

}

and this is the arduino code

Hi, with a quick look at your code I see that you are using the Serial Port for the Arduino to receive data and see it via the Serial Monitor…

So, your Arduino only has one hardware Serial Port. The OpenMV Cam is sending data to this serial port and then you are printing to this same serial port to the PC. What’s happening is that you are observing the device communication on your Serial Monitor.

You should create a second serial port using software serial to connect the camera to the Arduino…

I’ll look over your code in more detail in a bit to see what changes you can do to fix any issues…