QR code orientation With Arduino Nicla Vision

Photography of the Arduino Nicla Vision board used for reading QR code

Introduction

In the world of computer vision and IoT, compact devices like the Arduino Nicla Vision are proving that big things can come in small packages. With its powerful onboard camera and AI capabilities, the Nicla Vision is ideal for edge computing tasks—like scanning and interpreting QR codes in real time.

But what if you need more than just reading the code? What if your application depends on knowing how the QR code position and orientation?

In this page, we'll explore how to detect the position and orientation of a QR code using the Arduino Nicla Vision. Whether you're building an automated sorting system, a smart scanner, or simply want to add a layer of intelligence to your QR-based project, understanding orientation can be the key to more dynamic and reliable interactions.

Source Code

This script demonstrates how to use the Arduino Nicla Vision to detect QR codes using its built-in camera and visualize their orientation based on the corner coordinates. The script also includes optional IMU and ToF sensor integrations. Here is the Python source code used in the video:

import pyb # Import module for board related functions
import sensor # Import the module for sensor related functions
import image # Import module containing machine vision algorithms
import imu
from vl53l1x import VL53L1X
from machine import Pin, I2C

redLED = pyb.LED(1) # built-in red LED
blueLED = pyb.LED(3) # built-in blue LED

sensor.reset() # Initialize the camera sensor.
#sensor.set_pixformat(sensor.GRAYSCALE) # Sets the sensor to RGB
sensor.set_pixformat(sensor.RGB565) # Sets the sensor to RGB
sensor.set_framesize(sensor.QVGA) # Sets the resolution to 320x240 px
#sensor.set_framesize(sensor.VGA) # Sets the resolution to 480x320 px
#sensor.set_framesize(sensor.VGA) # Sets the resolution to 640x480 px
#sensor.set_framesize(sensor.XGA) # Sets the resolution to 640x480 px
#sensor.set_hflip(True) # Flips the image vertically
#sensor.set_hmirror(True) # Mirrors the image horizontally

redLED.on()
sensor.skip_frames(time = 100) # Skip some frames to let the image stabilize

redLED.off()
blueLED.on()

#tof = VL53L1X(I2C(2))

while(True):

    #distance = tof.read()
    #print(f"Distance: {distance}mm")

    #imu_pitch = imu.pitch()
    #imu_roll = imu.roll()
    #temperature = imu.temperature_c()
    img = sensor.snapshot()
    #img.to_grayscale()
    #print (distance, imu_pitch, imu_roll, temperature)

    for code in img.find_qrcodes():
        blueLED.on()
        print (code)
        img.draw_rectangle((code.x(), code.y(),code.w() ,code.h()),color=(255,0,0))
        img.draw_circle(code.corners()[0][0], code.corners()[0][1], 5,color=(0,255,0))
        img.draw_circle(code.corners()[1][0], code.corners()[1][1], 5,color=(0,0,255))
        img.draw_circle(code.corners()[2][0], code.corners()[2][1], 5,color=(0,0,255))
        img.draw_circle(code.corners()[3][0], code.corners()[3][1], 5,color=(0,0,255))

        #print("You're on camera!")
        #sensor.snapshot().save("example.jpg")
        blueLED.off()

#blueLED.off()
#print("Done! Reset the camera to see the saved image.")

Code Overview

Imports and Setup

import pyb
import sensor
import image
import imu
from vl53l1x import VL53L1X
from machine import Pin, I2C

LED Initialization

redLED = pyb.LED(1)
blueLED = pyb.LED(3)

Camera Configuration

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)

You could optionally flip or mirror the image depending on your hardware setup:

# sensor.set_hflip(True)
# sensor.set_hmirror(True)

Wait for Sensor Stability

redLED.on()
sensor.skip_frames(time = 100)
redLED.off()
blueLED.on()

Main Loop

while(True):
    img = sensor.snapshot()

QR Code Detection and Drawing

for code in img.find_qrcodes():
    blueLED.on()
    print(code)

Drawing and Orientation Hints

img.draw_rectangle((code.x(), code.y(),code.w() ,code.h()), color=(255,0,0))
img.draw_circle(code.corners()[0][0], code.corners()[0][1], 5, color=(0,255,0))
img.draw_circle(code.corners()[1][0], code.corners()[1][1], 5, color=(0,0,255))
img.draw_circle(code.corners()[2][0], code.corners()[2][1], 5, color=(0,0,255))
img.draw_circle(code.corners()[3][0], code.corners()[3][1], 5, color=(0,0,255))

Optional Sensor Integration (Commented Out)

# distance = tof.read()
# imu_pitch = imu.pitch()
# imu_roll = imu.roll()
# temperature = imu.temperature_c()

Final Touch

blueLED.off()

Summary

This script lays the foundation for a vision-based embedded system using Nicla Vision that can:

Download


Last update : 04/23/2025