Nicla Vision User Manual
Learn about the hardware and software features of the Arduino® Nicla Vision.
Overview
This user manual will guide you through a practical journey covering the most interesting features of the Arduino Nicla Vision. With this user manual, you will learn how to set up, configure and use this Arduino board.
Hardware and Software Requirements
Hardware Requirements
- Arduino Nicla Vision (x1)
- Micro USB cable (x1)
Software Requirements
- OpenMV IDE
- Arduino IDE 1.8.10+, Arduino IDE 2.0+, or Arduino Web Editor
- To create custom Machine Learning models, the Machine Learning Tools add-on integrated into the Arduino Cloud is needed. In case you do not have an Arduino Cloud account, you will need to create one first.
Product Overview
The Nicla Vision is a ready-to-use, standalone camera board for analyzing and processing images on the edge. Thanks to its 2 MP color camera, smart 6-axis motion sensor, integrated microphone, and distance sensor, it is suitable for asset tracking, object recognition, and predictive maintenance.
The Nicla Vision lets you quickly implement sensor nodes to send collected data to the Arduino® Cloud (or third-party vendor services) via its onboard Wi-Fi® and Bluetooth® module.
Board Architecture Overview
The Nicla Vision features a robust and efficient architecture that integrates a range of sensors packed into a tiny footprint. Nicla Vision combines a powerful STM32H747AII6 Dual Arm® Cortex®-M7/M4 IC processor with a 2MP color camera that supports TinyML, as well as a smart 6-axis motion sensor, integrated PDM microphone and a Time of Flight distance sensor.
Here is an overview of main components of the board, as shown in the images above:
- Camera: the Nicla Vision features a camera based on the GC2145 Color rolling shutter image sensor. The GC2145 incorporates a 1616V x 1232H active pixel array, on-chip 10-bit ADC, and an image signal processor. The 2MP GC2145 CMOS camera module is equipped with an 80° (DFOV) stock lens, 1.75 μm pixel size and a focal length of 2.2 mm. It supports RGB output format.
- Microcontroller: the heart of the Nicla Vision is the dual-core STM32H747 (U1), including an Arm® Cortex®-M7 running at 480 MHz and an Arm® Cortex®-M4 running at 240 MHz. The two cores communicate via a Remote Procedure Call mechanism that allows calling functions on the other processor seamlessly.
- Onboard advanced motion sensor: the board features the LSM6DSOX, a smart IMU that includes a 3-axis accelerometer and a 3-axis gyroscope. The LSM6DSOX has a full-scale acceleration range of ±2/±4/±8/±16 g and an angular rate range of ±125/±250/±500/±1000/±2000 dps.
- Onboard distance sensor: the VL53L1CBV0FY Time-of-Flight sensor (U4) adds accurate and low-power ranging capabilities to the Nicla Vision. The invisible near infrared VCSEL laser (including the analog driver) is encapsulated together with receiving optics in an all-in-one small module located below the camera.
- Digital Microphone: the MP34DT05 digital MEMS microphone (U6) is omnidirectional and operates via a capacitive sensing element with a high (64 dB) signal-to-noise ratio. The sensing element, capable of detecting acoustic waves, is manufactured using a specialized silicon micromachining process dedicated to audio sensors production.
- Wireless connectivity: the Murata® LBEE5KL1DX-883 wireless module (U9) simultaneously provides Wi-Fi® and Bluetooth® connectivity in an ultra-small package based on the Cypress CYW4343W. The IEEE802.11 b/g/n Wi-Fi® interface can operate as an access point (AP), station (STA), or dual-mode simultaneous AP/STA. It supports a maximum transfer rate of 65 Mbps. Bluetooth® interface supports Bluetooth® Classic and Bluetooth® Low Energy. An integrated antenna circuitry switch allows a single external antenna (J6) to be shared between Wi-Fi® and Bluetooth®.
- Power management: the Nicla Vision is designed for ultra-low power operation, with efficient power management features that ensure minimal energy consumption even when using always-on motion recognition and image processing. The Nicla Vision features the PF1550 from NXP®, a highly integrated battery charge management integrated circuit (IC) designed for wearables and Internet of Things (IoT) devices.
- Security Elements: the Nicla Vision enables IC level edge-to-cloud security capability through the NXP SE050C2 Crypto chip (U8). This provides Common Criteria EAL 6+ security certification up to OS level, as well as RSA/ECC cryptographic algorithm support and credential storage.
Board Core and Libraries
With OpenMV IDE
Before you can start programming MicroPython scripts for the Nicla Vision, you need to download and install the OpenMV IDE.
Open the OpenMV download page in your browser, download the latest version available for your operating system, and follow the instructions of the installer.
Open the OpenMV IDE and connect the Nicla Vision to your computer via the USB cable if you have not done so yet.
Click on the "connect" symbol at the bottom of the left toolbar.
If your Nicla Vision does not have the latest firmware, a pop-up will ask you to install it. Your board will enter in DFU mode and its green LED will start fading.
Select
Install the latest release firmware
. This will install the latest OpenMV firmware on the Nicla Vision. You can leave the option of erasing the internal file system unselected and click OK
.Nicla Vision's green LED will start flashing while the OpenMV firmware is being uploaded to the board. A loading bar will start showing you the flashing progress.
Wait until the green LED stops flashing and fading. You will see a message saying
DFU firmware update complete!
when the process is done.The board will start flashing its blue LED when it is ready to be connected. After confirming the completion dialog, the Nicla Vision should already be connected to the OpenMV IDE, otherwise, click the "connect" button (plug symbol) once again (the blue blinking should stop).
While using the Nicla Vision with OpenMV, the RGB LED of the board can be used to inform the user about its current status. Some of the most important ones are the following:
🟢 Blinking Green: Your Nicla Vision onboard bootloader is running. The onboard bootloader runs for a few seconds when your Nicla Vision is powered via USB to allow OpenMV IDE to reprogram your Nicla Vision.
🔵 Blinking Blue: Your Nicla Vision is running the default main.py script onboard.
If you overwrite the main.py script on your Nicla Vision, then it will run whatever code you loaded on it instead.
If the LED is blinking blue but OpenMV IDE cannot connect to your Nicla Vision, please make sure you are connecting your Nicla Vision to your PC with a USB cable that supplies both data and power.
⚪ Blinking White: Your Nicla Vision firmware is panicking because of a hardware failure. Please check that your Nicla Vision's camera module is installed securely.
If you tap the Nicla Vision reset button once, the board resets. If you tap it twice, the board enters in Device Firmware Upgrade (DFU) mode and its green LED starts blinking and fading.
With Arduino IDE
The Arduino Mbed OS Nicla Boards core contains the libraries and examples you need to work with the board's components, such as its camera and IMU. To install the core for Nicla boards, navigate to Tools > Board > Boards Manager or click the Boards Manager icon in the left tab of the IDE. In the Boards Manager tab, search for
Nicla Vision
and install the latest Arduino Mbed OS Nicla Boards
version.To update the bootloader firmware of your Nicla Vision, go to File > Examples > STM32H747_System > STM32H747_manageBootloader and upload this sketch to your board.
After the sketch is uploaded, follow the instructions in the Serial Monitor.
Pinout
The full pinout is available and downloadable as PDF from the link below:
Datasheet
The complete datasheet is available and downloadable as PDF from the link below:
Schematics
The complete schematics are available and downloadable as PDF from the link below:
STEP Files
The complete STEP files are available and downloadable from the link below:
First Use
Powering the Board
The Nicla Vision can be powered by:
- Using a Micro USB cable (not included).
- Using an external 5 V power supply connected to
pin (please, refer to the board pinout section of the user manual).VIN
- Using a 3.7 V Lithium Polymer (Li-Po) battery connected to the board through the onboard battery connector; the manufacturer part number of the battery connector is BM03B-ACHSS and its matching receptacle manufacturer part number is ACHR-03V-S. The recommended minimum battery capacity for the Nicla Vision is 200 mAh. A Li-Po battery with an integrated NTC thermistor is also recommended for thermal protection.
- Using the onboard ESLOV connector, which has a dedicated 5V power line.
Hello World Example
Let's program the Nicla Vision with the classic
hello world
example used in the Arduino ecosystem: the Blink
sketch. We will use this example to verify the board's connection to the IDEs and that the Nicla Vision core and the board itself are working as expected. With OpenMV
Copy and paste the code below into a new sketch in the OpenMV IDE.
1import time2from machine import LED3
4redLED = LED("LED_RED")5greenLED = LED("LED_GREEN")6blueLED = LED("LED_BLUE")7
8while True:9 redLED.on()10 time.sleep_ms(1000)11 redLED.off()12 time.sleep_ms(1000)13 greenLED.on()14 time.sleep_ms(1000)15 greenLED.off()16 time.sleep_ms(1000)17 blueLED.on()18 time.sleep_ms(1000)19 blueLED.off()20 time.sleep_ms(1000)
To run the code on the Nicla Vision, click the Connect button and then the Start button.
With Arduino IDE
Copy and paste the code below into a new sketch in the Arduino IDE.
1void setup() {2
3 pinMode(LEDR, OUTPUT);4 pinMode(LEDG, OUTPUT);5 pinMode(LEDB, OUTPUT);6
7 digitalWrite(LEDR, HIGH);8 digitalWrite(LEDG, HIGH);9 digitalWrite(LEDB, HIGH);10
11}12
13void loop() {14
15 digitalWrite(LEDR, LOW); // Nicla Vision LED's turn on with logic '0'16 delay(1000); 17 digitalWrite(LEDR, HIGH); 18 delay(1000); 19 digitalWrite(LEDG, LOW); 20 delay(1000); 21 digitalWrite(LEDG, HIGH); 22 delay(1000);23 digitalWrite(LEDB, LOW); 24 delay(1000); 25 digitalWrite(LEDB, HIGH); 26 delay(1000);27
28}
To upload the code to the Nicla Vision, click the Verify button to compile the sketch and check for errors; then click the Upload button to program the board with the sketch.
Results
You should now repeatedly see the onboard LED turning red, green, and blue.
Pins
Analog Pins
The Nicla Vision has three analog input pins, mapped as follows:
Microcontroller Pin | Arduino Pin Mapping |
---|---|
ADC1/PC_4 | A0 |
ADC2/PF_13 | A1 |
ADC3/PF_3 | A2 |
All of them can be used through the built-in functions of the Arduino programming language.
The Nicla Vision ADC reference voltage is fixed to 3.3V, this means that it will map the ADC range from 0 to 3.3 volts.
We will use the Nicla Vision analog inputs on both IDEs, OpenMV and Arduino. For the example codes shown below, we will be reading the analog input
A0
and displaying the read voltage on the Serial Monitor of both IDEs:With OpenMV
Using Micropython on the OpenMV IDE the Nicla boards ADC resolution is fixed to 12 bits (it's maximum).
This example code can also be found on File > Examples > Board Control > adc_read_ext_channel.py:
1import time2from pyb import ADC3
4adc = ADC("A0") # PC4 microcontroller port5
6while True:7 # The ADC has 12-bits of resolution for 4096 values.8 print(adc.read())9 print("ADC = %fv" % ((adc.read() * 3.3) / 4095))10 time.sleep_ms(100)
With Arduino IDE
Nicla boards ADC can be configured to 8, 10 or 12 bits defining the argument of the following function respectively (default is 10 bits):
1analogReadResolution(12); // ADC resolution set to 12 bits (0-4095)
Example code:
1int potPin = A0; // select the input pin for the potentiometer2
3void setup() {4 Serial.begin(115200);5 analogReadResolution(12);6}7
8void loop() {9 // read the value from the sensor:10 Serial.print("ADC = ");11 Serial.print((analogRead(potPin) * 3.3) / 4095);;12 Serial.println(" v");13 delay(100);14}
Digital Pins
The Nicla Vision has ten digital pins, mapped as follows:
Microcontroller Pin | Arduino Pin Mapping |
---|---|
PG_12 | D0 |
PA_9 | D1 |
PA_10 | D2 |
PG_1 | D3 |
PE_12 | SCK |
PE_13 | MISO |
PE_14 | MOSI |
PE_11 | SS |
PB_8 | I2C_SCL |
PB_9 | I2C_SDA |
Notice that I2C and SPI pins can also be used as digital pins. Please, refer to the board pinout section of the user manual to find them on the board.
The analog inputs of the Nicla Vision can be used as digital pins but they can just handle 1.8 V, a greater input may damage the board.
The digital pins of the Nicla Vision can be used as inputs or outputs through the built-in functions of the Arduino programming language.
The Nicla Vision digital I/O's are low power, so to drive output devices like LEDs, resistive loads, buzzers, etc, it is recommended to use a MOSFET driver or a buffer to guarantee the required current flow. Learn more about the Nicla I/O's considerations here.
As an application example after learning the Digital Pins basics, we are going to control an LED using a push button. See the wiring below:
With OpenMV
The configuration of a digital pin is done in the upper section of the code as shown below:
1# Pin configured as an input2pin1 = Pin("D1", Pin.IN, Pin.PULL_NONE) 3# Pin configured as an input, internal pull-up resistor enabled4pin1 = Pin("D1", Pin.IN, Pin.PULL_UP) 5# Pin configured as an output6pin0 = Pin("D0", Pin.OUT_PP, Pin.PULL_NONE)
The pin function can be set as:
Pin.IN
, Pin.OUT_PP
, Pin.OUT_OD
, Pin.AF_PP
, or Pin.AF_OD
. An explanation of the pin modes can be found here. The third parameter represents the pull-up/pull-down resistor. It can be set to: Pin.PULL_NONE
, Pin.PULL_UP
or Pin.PULL_DOWN
.The state of a digital pin, configured as an input, can be read as shown below:
1# Reads pin1 state, stores value in "state" variable2state = pin1.value()
The state of a digital pin, configured as an output, can be changed as shown below:
1# Set pin0 on2pin0.value(True) 3# Set pin0 off4pin0.value(False)
The example code shown below uses digital pin
D0
to control an LED and reads the state of a button connected to digital pin D1
:1import time2from machine import Pin3
4# Define button and LED pin5button = Pin("D1", Pin.IN, Pin.PULL_UP)6led = Pin("D0", Pin.OUT_PP, Pin.PULL_NONE)7
8while True:9 if button.value() == 0: # if the button is pressed10 led.value(1)11 print("- Button is pressed. LED is on.")12 else: # if the button is not pressed13 led.value(0)14 print("- Button is not pressed. LED is off.")15 time.sleep_ms(1000) # wait for a second
With Arduino IDE
The configuration of a digital pin is done in the
setup()
function with the built-in function pinMode()
as shown below:1// Pin configured as an input2pinMode(D1, INPUT); 3// Pin configured as an input, internal pull-up resistor enabled4pinMode(D1, INPUT_PULLUP); 5// Pin configured as an output6pinMode(D0, OUTPUT);
The state of a digital pin, configured as an input, can be read using the built-in function
digitalRead()
as shown below:1// Reads pin state, stores value in state variable2state = digitalRead(D1);
The state of a digital pin, configured as an output, can be changed using the built-in function
digitalWrite()
as shown below:1// Set pin on2digitalWrite(D0, HIGH); 3// Set pin off4digitalWrite(D0, LOW);
The example code shown below uses digital pin
D0
to control an LED and reads the state of a button connected to digital pin D1
:1// Define button and LED pin2int buttonPin = D1;3int ledPin = D0;4
5// Variable to store the button state6int buttonState = 0;7
8void setup() {9 // Configure button and LED pins10 pinMode(buttonPin, INPUT_PULLUP);11 pinMode(ledPin, OUTPUT);12 // Initialize Serial communication13 Serial.begin(115200);14}15
16void loop() {17 // Read the state of the button18 buttonState = digitalRead(buttonPin);19 // If the button is pressed, turn on the LED and print its state to the Serial Monitor20 if (buttonState == LOW) {21 digitalWrite(ledPin, HIGH);22 Serial.println("- Button is pressed. LED is on.");23 } else {24 // If the button is not pressed, turn off the LED and print to the Serial Monitor25 digitalWrite(ledPin, LOW);26 Serial.println("- Button is not pressed. LED is off.");27 }28 // Wait for 1000 milliseconds29 delay(1000);30}
PWM Pins
Most digital pins of the Nicla Vision can be used as PWM (Pulse Width Modulation) pins, including I2C and SPI interfaces.
With OpenMV
PWM outputs can be controlled with MicroPython easily by using built-in functions as shown below:
First, we need to identify the
Timer
and Channel
used by the PWM
output to be used. For this, search for the desired pin on the STM32H747 datasheet from page 89.Here is a table with the details of the exposed pins on the Nicla Vision:
Microcontroller Pin | Arduino Pin Mapping | Timer | Channel |
---|---|---|---|
PA_9 | D1 | TIMER1 | CH2 |
PA_10 | D2 | TIMER1 | CH3 |
PB_8 | I2C_SCL | TIMER4 | CH3 |
PB_9 | I2C_SDA | TIMER4 | CH4 |
PE_11 | SS | TIMER1 | CH2 |
PE_12 | SCK | TIMER1 | CH3 |
PE_13 | MISO | TIMER1 | CH3 |
PE_14 | MOSI | TIMER1 | CH4 |
To use the PWM functions, you need to import the
time
, Pin
, and Timer
modules.1import time2from pyb import Pin, Timer
First you need to choose the pin you want to use PWM with.
1OUT = Pin("D1", Pin.OUT_PP, Pin.PULL_NONE)
Create a timer for the PWM, where you set the
timer number
(following the table from above) and the frequency.1timer1 = Timer(1, freq=1000)
Then you need to start a
PWM channel
(following the table from above) with the timer object. 1channel1 = timer1.channel(2, Timer.PWM, pin=OUT, pulse_width_percentage=0)
Get or set the pulse width value on a channel. To get, pass no arguments. To set, give a value as an argument.
1channel1.pulse_width_percentage(Width) # Width (0-100)
As a complete example here is a code to generate a 50% duty cycle PWM signal at 1 Mhz.
1import time2from pyb import Pin, Timer3
4# D1 is connected to TIMER1_CH25
6OUT = Pin("D1")7
8timer1 = Timer(1, freq=1000000)9channel1 = timer1.channel(2, Timer.PWM, pin=OUT, pulse_width_percent=0)10
11channel1.pulse_width_percent(50)12
13
14while True:15 time.sleep_ms(1000)
With Arduino IDE
This functionality can be used with the built-in function
analogWrite()
as shown below:1analogWrite(pin, value);
The output resolution is 8 bits by default, so the output value should be between 0 and 255. To set a greater resolution, you can use the built-in function
analogWriteResolution
as shown below:1analogWriteResolution(bits);
Using
analogWrite
has some limitations, for example, the PWM signal frequency is fixed at 763 Hz, and this could not be ideal for every application.1// 12 bits PWM 50% duty cycle example code2
3void setup() {4 analogWriteResolution(12); // 12 bits (0-4095)5}6
7void loop() {8 analogWrite(D1, 2048); // PWM output on D19}
Onboard Sensors
The Nicla Vision comes with various onboard sensors that allow you to capture and process motion data via a 6-axis IMU, distance with a Time of Flight (ToF) sensor, record sound with a PDM microphone, and capture images and videos with a camera.
The onboard sensors can be used for developing various applications, such as voice commanded projects, activity recognition, vibration detection and image classification. The onboard sensors are suitable for Machine Learning applications using our Arduino Cloud ML Tools.
IMU
The Nicla Vision features an advanced IMU, which allows the board to sense motion. The IMU on the board is the LSM6DSOXTR from ST®. It consists of a 3-axis accelerometer and a 3-axis gyroscope. They can provide information about the board's motion, orientation, and rotation in a 3D space.
With OpenMV
In this MicroPython environment, you can choose between a basic usage of the IMU by sampling raw motion data using the example code below.
1import time2from lsm6dsox import LSM6DSOX3from machine import Pin4from machine import SPI5
6lsm = LSM6DSOX(SPI(5), cs=Pin("PF6", Pin.OUT_PP, Pin.PULL_UP))7
8while True:9 print("Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}".format(*lsm.accel()))10 print("Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}".format(*lsm.gyro()))11 print("")12 time.sleep_ms(100)
Also, you can develop Machine Learning applications using the Nicla Vision IMU. As a practical example, we are going to test a
Vibration monitoring
model that will be able to identify three states: no vibration
, low vibration
and high vibration
.First, download the pre-trained model file from the example repository and copy it to the Nicla Vision storage drive.
Reset the board and run the following code on the OpenMV IDE.
1from machine import Pin2from machine import SPI3from lsm6dsox import LSM6DSOX4
5INT_MODE = True # Run in interrupt mode.6INT_FLAG = False # Set True on interrupt.7
8
9def imu_int_handler(pin):10 global INT_FLAG11 INT_FLAG = True12
13
14if INT_MODE is True:15 int_pin = Pin("PA1", mode=Pin.IN, pull=Pin.PULL_UP)16 int_pin.irq(handler=imu_int_handler, trigger=Pin.IRQ_RISING)17
18# Vibration detection example19UCF_FILE = "lsm6dsox_vibration_monitoring.ucf"20UCF_LABELS = {0: "no vibration", 1: "low vibration", 2: "high vibration"}21# NOTE: Selected data rate and scale must match the MLC data rate and scale.22lsm = LSM6DSOX(23 SPI(5),24 cs=Pin("PF6", Pin.OUT_PP, Pin.PULL_UP),25 gyro_odr=26,26 accel_odr=26,27 gyro_scale=2000,28 accel_scale=4,29 ucf=UCF_FILE,30)31
32print("MLC configured...")33
34while True:35 if INT_MODE:36 if INT_FLAG:37 INT_FLAG = False38 print(UCF_LABELS[lsm.mlc_output()[0]])39 else:40 buf = lsm.mlc_output()41 if buf is not None:42 print(UCF_LABELS[buf[0]])
In the OpenMV IDE Serial Monitor, the inference results will be printed after a vibration event.
You can download and test many other pre-trained models available in this repository.
With Arduino IDE
First, to use this sensor with the Arduino IDE, you need to install the
Arduino_LSM6DSOX
library, which can be found in the Arduino IDE library manager. To do so in the IDE, select it from the left side menu, search for LSM6DSOX
and install the one from Arduino.The example code below shows how to get acceleration and angular velocity data from the onboard IMU and stream it to the IDE's Serial Monitor and Serial Plotter.
1#include <Arduino_LSM6DSOX.h>2
3void setup() {4 Serial.begin(9600);5 while (!Serial)6 ;7
8 if (!IMU.begin()) {9 Serial.println("Failed to initialize IMU!");10
11 while (1)12 ;13 }14
15 Serial.print("Accelerometer sample rate = ");16 Serial.print(IMU.accelerationSampleRate());17 Serial.println(" Hz");18 Serial.println();19 Serial.println("Acceleration in g's");20 Serial.println("X\tY\tZ");21
22 Serial.print("Gyroscope sample rate = ");23 Serial.print(IMU.gyroscopeSampleRate());24 Serial.println(" Hz");25 Serial.println();26 Serial.println("Gyroscope in degrees/second");27 Serial.println("X\tY\tZ");28
29 delay(3000); // Wait 3 seconds30}31
32void loop() {33 float a_x, a_y, a_z;34
35 if (IMU.accelerationAvailable()) {36 IMU.readAcceleration(a_x, a_y, a_z);37
38 Serial.print("acc_X:");39 Serial.print(a_x);40 Serial.print(",");41 Serial.print("acc_Y:");42 Serial.print(a_y);43 Serial.print(",");44 Serial.print("acc_Z:");45 Serial.println(a_z);46 }47 float g_x, g_y, g_z;48
49 if (IMU.gyroscopeAvailable()) {50 IMU.readGyroscope(g_x, g_y, g_z);51
52 Serial.print("gyro_X:");53 Serial.print(g_x);54 Serial.print(",");55 Serial.print("gyro_Y:");56 Serial.print(g_y);57 Serial.print(",");58 Serial.print("gyro_Z:");59 Serial.println(g_z);60 }61}
To test a Machine Learning model on the Arduino IDE, navigate to File > Examples > MLC > NiclaVision_MLC_Motion_Intesity and it will identify three scenarios:
, Stationary
and Medium Intensity
movements.High Intensity
Microphone
The onboard high-performance microphone of the Nicla Vision is the MP34DT06JTR from ST®. It is specifically designed for applications that require high-quality audio recording and accurate voice detection, such as voice-controlled Internet of Things (IoT) devices, smart home systems, and mobile devices.
Using OpenMV
The OpenMV IDE includes some examples to get started using the Nicla Vision onboard microphone that can be found on File > Examples > Audio. We are going to use the one called
micro_speech.py
to test the machine-learning speech recognition capabilities of the board.First, download the pre-trained model file from the example repository and copy it to the Nicla Vision storage drive.
Reset the board and run the following code on the OpenMV IDE.
1import audio2import time3import tf4import micro_speech5import pyb6
7labels = ["Silence", "Unknown", "Yes", "No"]8
9led_red = pyb.LED(1)10led_green = pyb.LED(2)11
12model = tf.load("/model.tflite")13speech = micro_speech.MicroSpeech()14audio.init(channels=1, frequency=16000, gain=24, highpass=0.9883)15
16# Start audio streaming17audio.start_streaming(speech.audio_callback)18
19while True:20 # Run micro-speech without a timeout and filter detections by label index.21 idx = speech.listen(model, timeout=0, threshold=0.70, filter=[2, 3])22 led = led_green if idx == 2 else led_red23 print(labels[idx])24 for i in range(0, 4):25 led.on()26 time.sleep_ms(25)27 led.off()28 time.sleep_ms(25)29
30# Stop streaming31audio.stop_streaming()
After running the code, the matches will be printed on the Serial Monitor if the board hears a
No
or a Yes
, turning on the red and green LED respectively.Using Arduino IDE
The Arduino IDE includes a simple example to visualize raw data from the PDM microphone. To test it, navigate to File > Examples > PDM > PDMSerialPlotter.
1#include <PDM.h>2
3// default number of output channels4static const char channels = 1;5
6// default PCM output frequency7static const int frequency = 16000;8
9// Buffer to read samples into, each sample is 16-bits10short sampleBuffer[512];11
12// Number of audio samples read13volatile int samplesRead;14
15void setup() {16 Serial.begin(9600);17 while (!Serial);18
19 // Configure the data receive callback20 PDM.onReceive(onPDMdata);21
22 // Optionally set the gain23 // Defaults to 20 on the BLE Sense and 24 on the Portenta Vision Shield24 // PDM.setGain(30);25
26 // Initialize PDM with:27 // - one channel (mono mode)28 // - a 16 kHz sample rate for the Arduino Nano 33 BLE Sense29 // - a 32 kHz or 64 kHz sample rate for the Arduino Portenta Vision Shield30 if (!PDM.begin(channels, frequency)) {31 Serial.println("Failed to start PDM!");32 while (1);33 }34}35
36void loop() {37 // Wait for samples to be read38 if (samplesRead) {39
40 // Print samples to the serial monitor or plotter41 for (int i = 0; i < samplesRead; i++) {42 if(channels == 2) {43 Serial.print("L:");44 Serial.print(sampleBuffer[i]);45 Serial.print(" R:");46 i++;47 }48 Serial.println(sampleBuffer[i]);49 }50
51 // Clear the read count52 samplesRead = 0;53 }54}55
56/**57 * Callback function to process the data from the PDM microphone.58 * NOTE: This callback is executed as part of an ISR.59 * Therefore using `Serial` to print messages inside this function isn't supported.60 * */61void onPDMdata() {62 // Query the number of available bytes63 int bytesAvailable = PDM.available();64
65 // Read into the sample buffer66 PDM.read(sampleBuffer, bytesAvailable);67
68 // 16-bit, 2 bytes per sample69 samplesRead = bytesAvailable / 2;70}
Upload the example code to the Nicla Vision and open the Serial Plotter to see the sound wave output.
Time of Flight (Distance) Sensor
The onboard ToF sensor of the Nicla Vision is the VL53L1CBV0FY from ST®. It adds accurate and low power ranging capabilities to the Nicla Vision. The invisible near-infrared VCSEL laser (including the analog driver) is encapsulated with receiving optics in an all-in-one small module located below the camera.
Here are listed the sensor's main features:
- Up to 400 cm distance measurement
- Up to 50 Hz ranging frequency
- 27° field-of-view (FoV)
With OpenMV
The OpenMV IDE includes an example to start using the ToF sensor. To test it, navigate to File > Examples > Sensors > vl53l1x_tof and run it on the Nicla Vision.
1from machine import I2C2from vl53l1x import VL53L1X3import time4
5tof = VL53L1X(I2C(2))6
7while True:8 print(f"Distance: {tof.read()}mm")9 time.sleep_ms(50)
With Arduino IDE
To use the ToF sensor with the Arduino IDE, install the
VL53L1X
library authored by Pololu by searching for it on the IDE library manager and clicking on install.Once installed, you will be able to compile and upload the example code below to your Nicla Vision.
The distance measured by the sensor will be printed on the IDE's Serial Monitor, and the built-in LED will blink proportionally to that distance.
1#include "VL53L1X.h"2VL53L1X proximity;3
4bool blinkState = false;5int reading = 0;6int timeStart = 0;7int blinkTime = 2000;8
9void setup() {10 Serial.begin(115200);11 Wire1.begin();12 Wire1.setClock(400000); // use 400 kHz I2C13 proximity.setBus(&Wire1);14
15
16 pinMode(LEDB, OUTPUT);17 digitalWrite(LEDB, blinkState);18
19 if (!proximity.init()) {20 Serial.println("Failed to detect and initialize sensor!");21 while (1);22 }23
24 proximity.setDistanceMode(VL53L1X::Long);25 proximity.setMeasurementTimingBudget(50000);26 proximity.startContinuous(50);27}28
29void loop() {30 reading = proximity.read();31 Serial.print(reading);32 Serial.println(" mm");33
34 if (millis() - timeStart >= reading) {35 digitalWrite(LEDB, blinkState);36 timeStart = millis();37
38 blinkState = !blinkState;39 }40}
Camera
The Nicla Vision's main feature is its onboard 2MP camera, based on the GC2145 color rolling shutter image sensor. It is perfect for Machine Learning applications such as object detection, image classification, machine/computer vision, robotics, IoT, and more.
The Nicla Vision is primarily intended to be used with the OpenMV MicroPython ecosystem. So, it's recommended to use this IDE for machine vision applications.
With OpenMV
The OpenMV IDE is designed to work specifically with machine/computer vision hardware, it is optimized for easy and fast development of image processing applications with a MicroPython framework and streaming monitors, color data graphics, and more.
The Nicla Vision uses a 2MP camera sensor, meaning its maximum resolution is 1920x1080 pixels. However, the effective resolution is 1616(H) × 1232(V).
Here we have the minimum code necessary to make the camera work streaming live video on the OpenMV IDE:
1import sensor2import time3
4sensor.reset() # Reset and initialize the sensor.5sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)6sensor.set_framesize(sensor.QVGA) # Set frame size to QVGA (320x240)7sensor.skip_frames(time=2000) # Wait for settings take effect.8clock = time.clock() # Create a clock object to track the FPS.9
10while True:11 clock.tick() # Update the FPS clock.12 img = sensor.snapshot() # Take a picture and return the image.13 print(clock.fps()) # Note: OpenMV Cam runs about half as fast when connected14 # to the IDE. The FPS should increase once disconnected.
From the above example script, we can highlight the main functions:
lets you set the pixel format for the camera sensor. The Nicla Vision is compatible with these:sensor.set_pixformat(<Sensor>)
,sensor.GRAYSCALE
,sensor.RGB565
, andsensor.BAYER
.sensor.YUV422
To define the pixel format to any of the supported ones, just add it to the
function argument.set_pixformat
lets you define the image frame size in terms of pixels. Here you can find all the different options.sensor.set_framesize(<Resolution>)
lets you take a picture and return the image so you can save it, stream it or process it.sensor.snapshot()
The example code below lets you take a picture and save it on the Nicla Vision local storage as
example.jpg
.1import sensor2import time3import machine4
5sensor.reset() # Reset and initialize the sensor.6sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)7sensor.set_framesize(sensor.QVGA) # Set frame size to QVGA (320x240)8sensor.skip_frames(time=2000) # Wait for settings take effect.9
10led = machine.LED("LED_BLUE")11
12start = time.ticks_ms()13while time.ticks_diff(time.ticks_ms(), start) < 3000:14 sensor.snapshot()15 led.toggle()16
17led.off()18
19img = sensor.snapshot()20img.save("example.jpg") # or "example.bmp" (or others)21
22raise (Exception("Please reset the camera to see the new file."))
After the snapshot is taken, reset the board by pressing the reset button and the image will be on the board storage drive.
The example code below lets you record a video and save it on the Nicla Vision local storage as
example.mjpeg
.1import sensor2import time3import mjpeg4import machine5
6sensor.reset() # Reset and initialize the sensor.7sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)8sensor.set_framesize(sensor.QVGA) # Set frame size to QVGA (320x240)9sensor.skip_frames(time=2000) # Wait for settings take effect.10
11led = machine.LED("LED_RED")12
13led.on()14m = mjpeg.Mjpeg("example.mjpeg")15
16clock = time.clock() # Create a clock object to track the FPS.17for i in range(200):18 clock.tick()19 m.add_frame(sensor.snapshot())20 print(clock.fps())21
22m.close(clock.fps())23led.off()24
25raise (Exception("Please reset the camera to see the new file."))
After the video is recorded, reset the board by pressing the reset button and the file will be on the board storage drive.
We recommend using VLC to play the video due to the format.
The next example lets you live stream what the camera sees through HTTP so you can watch it on your favorite browser from any device connected to the same network as the Nicla Vision.
Make sure to fill in the
SSID
and KEY
variables with your Wi-Fi® credentials.1import sensor2import time3import network4import socket5
6SSID = "*********" # Network SSID7KEY = "************" # Network key8HOST = "" # Use first available interface9PORT = 8080 # Arbitrary non-privileged port10
11# Init sensor12sensor.reset()13sensor.set_framesize(sensor.QVGA)14sensor.set_pixformat(sensor.RGB565)15
16# Init wlan module and connect to network17wlan = network.WLAN(network.STA_IF)18wlan.active(True)19wlan.connect(SSID, KEY)20
21while not wlan.isconnected():22 print('Trying to connect to "{:s}"...'.format(SSID))23 time.sleep_ms(1000)24
25# We should have a valid IP now via DHCP26print("WiFi Connected ", wlan.ifconfig())27
28# Create server socket29s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)30s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)31
32# Bind and listen33s.bind([HOST, PORT])34s.listen(5)35
36# Set server socket to blocking37s.setblocking(True)38
39
40def start_streaming(s):41 print("Waiting for connections..")42 client, addr = s.accept()43 # set client socket timeout to 5s44 client.settimeout(5.0)45 print("Connected to " + addr[0] + ":" + str(addr[1]))46
47 # Read request from client48 data = client.recv(1024)49 # Should parse client request here50
51 # Send multipart header52 client.sendall(53 "HTTP/1.1 200 OK\r\n"54 "Server: OpenMV\r\n"55 "Content-Type: multipart/x-mixed-replace;boundary=openmv\r\n"56 "Cache-Control: no-cache\r\n"57 "Pragma: no-cache\r\n\r\n"58 )59
60 # FPS clock61 clock = time.clock()62
63 # Start streaming images64 # NOTE: Disable IDE preview to increase streaming FPS.65 while True:66 clock.tick() # Track elapsed milliseconds between snapshots().67 frame = sensor.snapshot()68 cframe = frame.compressed(quality=35)69 header = (70 "\r\n--openmv\r\n"71 "Content-Type: image/jpeg\r\n"72 "Content-Length:" + str(cframe.size()) + "\r\n\r\n"73 )74 client.sendall(header)75 client.sendall(cframe)76 print(clock.fps())77
78
79while True:80 try:81 start_streaming(s)82 except OSError as e:83 print("socket error: ", e)84 # sys.print_exception(e)
Once you run this script, the Nicla Vision IP address will be printed on the OpenMV serial monitor after the Wi-Fi® connection processes.
To watch the live stream, enter the device IP address followed by the
:8080
port as follows:<Nicla Vision IP>:8080
To expand your knowledge using the Nicla Vision camera with MicroPython, try other built-in examples within the OpenMV IDE.
Machine Learning Tools
The Nicla Vision is a ready-to-use, standalone camera board, ready for analyzing and processing images on the Edge. Thanks to its 2MP color camera, smart 6-axis motion sensor, integrated microphone, and distance sensor, it is suitable for almost infinite machine-learning applications.
Creating this type of application has never been easier thanks to our Machine Learning Tool powered by Edge Impulse®, where we can easily create in a No-Code environment, Audio, Motion, Proximity and Image processing models.
The first step to start creating awesome artificial intelligence and machine learning projects is to create an Arduino Cloud account.
There you will find a dedicated integration called Machine Learning Tools.
Once in, create a new project and give it a name.
Enter your newly created project and the landing page will look like the following:
Edge Impulse® Environment Setup
Now, it is time to set up the Edge Impulse® environment on your PC. For this, follow these instructions to install the Edge Impulse CLI.
For Windows users: make sure to install Visual Studio Community andVisual Studio Build Tools.
Download and install the latest Arduino CLI from here. (Video Guide for Windows)
Download the latest Edge Impulse® firmware, and unzip the file.
Open the flash script for your operating system (
,flash_windows.bat
orflash_mac.command
) to flash the firmware.flash_linux.sh
To test if the Edge Impulse CLI was installed correctly, open the Command Prompt or your favorite terminal and run:
edge-impulse-daemon
If everything went okay, you should be asked for your account credentials.
Enter your account username or e-mail address and your password.
Select the project you have created on the Arduino ML Tools, it will be listed.
Give your device a name and wait for it to connect to the platform.
Uploading Sensor Data
The first thing to start developing a machine learning project is to create a dataset for your model. This means, uploading data to your model from any of the Nicla Vision sensors.
To upload data from your Nicla Vision on the Machine Learning Tools platform, navigate to Data Acquisition.
In this section, you will be able to select the Nicla Vision onboard sensors individually or several interesting combinations.
This is the supported sensors list:
- Built-in microphone
- Inertial (IMU)
- ADC sensor (A0)
- Proximity sensor
- Camera (different resolutions)
Now you know how to start with our Machine Learning Tools creating your dataset from scratch, you can get inspired by some of our ML projects listed below:
- Image Classification with Edge Impulse® (Article).
- Glass-Breaking Detector using Edge Impulse® (Video).
Communication
This section of the user manual covers the different communication protocols that are supported by the Nicla Vision, including the Serial Peripheral Interface (SPI), Inter-Integrated Circuit (I2C), Universal Asynchronous Receiver-Transmitter (UART), and Bluetooth® Low Energy; communication via the onboard ESLOV connector is also explained in this section. The Nicla Vision features dedicated pins for each communication protocol, making connecting and communicating with different components, peripherals, and sensors easy.
SPI
The Nicla Vision supports SPI communication, which allows data transmission between the board and other SPI-compatible devices. The pins used in the Nicla Vision for the SPI communication protocol are the following:
Microcontroller Pin | Arduino Pin Mapping |
---|---|
SCLK / PE_12 | SCK or 9 |
CIPO / PE_13 | MISO or 10 |
COPI / PE_14 | MOSI or 8 |
CS / PE_11 | SS or 7 |
Please, refer to the board pinout section of the user manual to localize them on the board.
With OpenMV
Import the
SPI
submodule from the pyb
module at the top of your sketch alongside time
and Pin
to use the SPI communication protocol. The SPI driver provides functions for SPI communication:1import time2from pyb import Pin, SPI
Before your infinite loop, configure the chip select (
CS
) pin and initialize the SPI peripheral as a Master
:1spi = SPI(4, SPI.MASTER, baudrate=int(480000000 / 256), polarity=0, phase=0)
To send data over SPI, use:
1spi.send(<data>) # add the data (integer or buffer) to be sent as the argument
To receive data over SPI, use:
1spi.recv(<bytes>) # add the number of bytes to be received as the argument
Here is a simple example showing how to send data over SPI.
1import time2from pyb import Pin, SPI3
4cs = Pin("SS", Pin.OUT_OD) # CS pin = PE115
6spi = SPI(4, SPI.MASTER, baudrate=int(480000000 / 256), polarity=0, phase=0)7
8while True:9 # Replace with the target device's address10 address = 0x3511 # Replace with the value to send12 value = 0xFA13 # Pull the CS pin LOW to select the device14 cs.low()15 # Send the address16 spi.send(address)17 # Send the value18 spi.send(value)19 # Pull the CS pin HIGH to unselect the device20 cs.high()21 22 time.sleep_ms(1000)
The example code above should output this:
With Arduino IDE
Include the
SPI
library at the top of your sketch to use the SPI communication protocol. The SPI library provides functions for SPI communication:1#include <SPI.h>
In the
setup()
function, initialize the SPI library, define and configure the chip select (CS
) pin:1void setup() {2 // Set the chip select pin as output3 pinMode(SS, OUTPUT); 4 // Pull the CS pin HIGH to unselect the device5 digitalWrite(SS, HIGH); 6 7 // Initialize the SPI communication8 SPI.begin();9}
To transmit data to an SPI-compatible device, you can use the following commands:
1// Replace with the target device's address2byte address = 0x35; 3// Replace with the value to send4byte value = 0xFA; 5// Pull the CS pin LOW to select the device6digitalWrite(SS, LOW); 7// Send the address8SPI.transfer(address); 9// Send the value10SPI.transfer(value); 11// Pull the CS pin HIGH to unselect the device12digitalWrite(SS, HIGH);
Here is the complete sketch for a simple SPI communication:
1#include <SPI.h>2
3void setup(){4 // Set the chip select pin as output5 pinMode(SS, OUTPUT); 6 // Pull the CS pin HIGH to unselect the device7 digitalWrite(SS, HIGH); 8 9 // Initialize the SPI communication10 SPI.begin();11}12
13void loop(){14 // Replace with the target device's address15 byte address = 0x35; 16 // Replace with the value to send17 byte value = 0xFA; 18 // Pull the CS pin LOW to select the device19 digitalWrite(SS, LOW); 20 // Send the address21 SPI.transfer(address); 22 // Send the value23 SPI.transfer(value); 24 // Pull the CS pin HIGH to unselect the device25 digitalWrite(SS, HIGH); 26 delay(1000);27}
The example code above should output this:
I2C
The Nicla Vision supports I2C communication, which allows data transmission between the board and other I2C-compatible devices. The pins used in the Nicla Vision for the I2C communication protocol are the following:
Microcontroller Pin | Arduino Pin Mapping |
---|---|
PB_8 | I2C_SCL or 12 |
PB_9 | I2C_SDA or 11 |
Please, refer to the board pinout section of the user manual to localize them on the board. The I2C pins are also available through the onboard ESLOV connector of the Nicla Vision.
With OpenMV
To use I2C communication with OpenMV, import
I2C
from the pyb
module as follows.1from pyb import I2C
Create the I2C objects and initialize them attached to a specific bus, below are some of the available commands to do it.
1i2c = I2C(1) # create on bus 12i2c = I2C(1, I2C.MASTER) # create and init as a master3i2c.init(I2C.MASTER, baudrate=20000) # init as a master4i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address5i2c.deinit() # turn off the peripheral
The basic methods are
send
and recv
implemented as follows:1# For Masters / Controllers (must include addr in send)2i2c.send('abc', 0x42) # send 3 bytes to device on address 0x423
4# For Slaves / Peripherals5i2c.send('abc') # send 3 bytes6i2c.send(0x42) # send a single byte, given by the number7
8data = i2c.recv(3) # receive 3 bytes
This is a simple example showing how to send data over I2C from a master to a slave.
1from pyb import I2C2
3i2c = I2C(1, I2C.MASTER)4
5buf = bytearray(2)6
7buf[0] = 0x008buf[1] = 0xFA9
10i2c.send(buf, 0x35)
The output data should look like the image below, where we can see the device address data frame:
To learn more about the I2C class on MicroPython, continue here.
With Arduino IDE
To use I2C communication, include the
Wire
library at the top of your sketch. The Wire
library provides functions for I2C communication:1#include <Wire.h>
In the
setup()
function, initialize the I2C library:1// Initialize the I2C communication2Wire.begin();
To transmit data to an I2C-compatible device, you can use the following commands:
1// Replace with the target device's I2C address2byte deviceAddress = 0x35; 3// Replace with the appropriate instruction byte4byte instruction = 0x00; 5// Replace with the value to send6byte value = 0xFA; 7// Begin transmission to the target device8Wire.beginTransmission(deviceAddress); 9// Send the instruction byte10Wire.write(instruction); 11// Send the value12Wire.write(value); 13// End transmission14Wire.endTransmission();
The output data should look like the image below, where we can see the device address data frame:
Here is the complete sketch for a simple I2C communication:
1#include <Wire.h>2
3void setup(){4 // Initialize the I2C communication5 Wire.begin();6}7
8void loop(){9 // Replace with the target device's I2C address10 byte deviceAddress = 0x35; 11 // Replace with the appropriate instruction byte12 byte instruction = 0x00; 13 // Replace with the value to send14 byte value = 0xFA; 15 // Begin transmission to the target device16 Wire.beginTransmission(deviceAddress); 17 // Send the instruction byte18 Wire.write(instruction); 19 // Send the value20 Wire.write(value); 21 // End transmission22 Wire.endTransmission(); 23 delay(1000);24}
To read data from an I2C-compatible device, you can use the
requestFrom()
function to request data from the device and the read()
function to read the received bytes:1// The target device's I2C address2byte deviceAddress = 0x1; 3// The number of bytes to read4int numBytes = 2; 5// Request data from the target device6Wire.requestFrom(deviceAddress, numBytes);7// Read while there is data available8while (Wire.available()) {9 byte data = Wire.read(); 10}
UART
The pins used in the Nicla Vision for the UART (external) communication protocol are the following:
Microcontroller Pin | Arduino Pin Mapping |
---|---|
PA_10 | SERIAL1_RX |
PA_9 | SERIAL1_TX |
Please, refer to the board pinout section of the user manual to localize them on the board.
With OpenMV
To begin with UART communication, you will need to import
UART
from the machine
module.1from machine import UART
Then, initialize the UART object defining the bus number and baudrate.
1uart = UART(9, 115200) # bus 9 uses PA9 and PA10 as (TX and RX) respectively
To read incoming data, you can use different functions as the following.
1uart.read(10) # read 10 characters, returns a bytes object2uart.read() # read all available characters3uart.readline() # read a line4uart.readinto(buf) # read and store into the given buffer
To write data, use the following function.
1uart.write('abc') # write the 3 characters
Here is the complete example that writes "Hello World!" on the external serial port of the Nicla Vision.
1import time2from machine import UART3
4# Init UART object.5uart = UART(9, 115200)6
7while True:8 uart.write("Hello World!\r")9 time.sleep_ms(1000)
This is the output of the example code from above.
With Arduino IDE
To begin with UART communication, you will need to configure it first. In the
setup()
function, set the baud rate (bits per second) for UART communication:1// Start UART communication at 115200 baud2Serial1.begin(115200); // Serial1 for the external UART pins | Serial for the internal virtual/monitor UART
Using the Arduino IDE, the minimum supported baud rate is 19200.
To read incoming data, you can use a
while()
loop to continuously check for available data and read individual characters. The code shown above stores the incoming characters in a String variable and processes the data when a line-ending character is received:1// Variable for storing incoming data2String incoming = ""; 3void loop() {4 // Check for available data and read individual characters5 while (Serial1.available()) {6 // Allow data buffering and read a single character7 delay(2); 8 char c = Serial1.read();9 10 // Check if the character is a newline (line-ending)11 if (c == '\n') {12 // Process the received data13 processData(incoming);14 // Clear the incoming data string for the next message15 incoming = ""; 16 } else {17 // Add the character to the incoming data string18 incoming += c; 19 }20 }21}
To transmit data to another device via UART, you can use the
write()
function:1// Transmit the string "Hello world!2Serial1.write("Hello world!");
You can also use the
print
and println()
to send a string without a newline character or followed by a newline character:1// Transmit the string "Hello world!" 2Serial1.print("Hello world!");3// Transmit the string "Hello world!" followed by a newline character4Serial1.println("Hello world!");
If you want to communicate through the USB serial port, use "Serial" instead of "Serial1" for this case.
Bluetooth® Low Energy
To enable the Bluetooth® Low Energy communication on the Nicla Vision, you can use the
bluetooth
module in OpenMV or the ArduinoBLE library in the Arduino IDE.We are going to build a Bluetooth® LE temperature monitor that using the nRF Connect app (available for Android and iOS) will let us easily connect to our Nicla Vision and monitor the temperature in real time.
With OpenMV
For this Bluetooth® LE application example, we are going to emulate the temperature sensor. Below you will find the complete sketch.
1import bluetooth2import random3import struct4import time5from ble_advertising import advertising_payload6from machine import LED7from micropython import const8
9_IRQ_CENTRAL_CONNECT = const(1)10_IRQ_CENTRAL_DISCONNECT = const(2)11_IRQ_GATTS_INDICATE_DONE = const(20)12
13_FLAG_READ = const(0x0002)14_FLAG_NOTIFY = const(0x0010)15_FLAG_INDICATE = const(0x0020)16
17# org.bluetooth.service.environmental_sensing18_ENV_SENSE_UUID = bluetooth.UUID(0x181A)19# org.bluetooth.characteristic.temperature20_TEMP_CHAR = (21 bluetooth.UUID(0x2A6E),22 _FLAG_READ | _FLAG_NOTIFY | _FLAG_INDICATE,23)24_ENV_SENSE_SERVICE = (25 _ENV_SENSE_UUID,26 (_TEMP_CHAR,),27)28
29# org.bluetooth.characteristic.gap.appearance.xml30_ADV_APPEARANCE_GENERIC_THERMOMETER = const(768)31
32
33class BLETemperature:34 def __init__(self, ble, name="Py Temp Sensor"):35 self._ble = ble36 self._ble.active(True)37 self._ble.irq(self._irq)38 ((self._handle,),) = self._ble.gatts_register_services((_ENV_SENSE_SERVICE,))39 self._connections = set()40 self._payload = advertising_payload(41 name=name,42 services=[_ENV_SENSE_UUID],43 appearance=_ADV_APPEARANCE_GENERIC_THERMOMETER,44 )45 self._advertise()46 self.led = LED("LED_BLUE")47
48 def _irq(self, event, data):49 # Track connections so we can send notifications.50 if event == _IRQ_CENTRAL_CONNECT:51 conn_handle, _, _ = data52 self._connections.add(conn_handle)53 self.led.on()54 elif event == _IRQ_CENTRAL_DISCONNECT:55 conn_handle, _, _ = data56 self._connections.remove(conn_handle)57 # Start advertising again to allow a new connection.58 self._advertise()59 self.led.off()60 elif event == _IRQ_GATTS_INDICATE_DONE:61 conn_handle, value_handle, status = data62
63 def set_temperature(self, temp_deg_c, notify=False, indicate=False):64 # Data is sint16 in degrees Celsius with a resolution of 0.01 degrees Celsius.65 # Write the local value, ready for a central to read.66 self._ble.gatts_write(self._handle, struct.pack("<h", int(temp_deg_c * 100)))67 if notify or indicate:68 for conn_handle in self._connections:69 if notify:70 # Notify connected centrals.71 self._ble.gatts_notify(conn_handle, self._handle)72 if indicate:73 # Indicate connected centrals.74 self._ble.gatts_indicate(conn_handle, self._handle)75
76 def _advertise(self, interval_us=500000):77 self._ble.gap_advertise(interval_us, adv_data=self._payload)78
79
80if __name__ == "__main__":81 ble = bluetooth.BLE()82 temp = BLETemperature(ble)83
84 t = 2585 i = 086
87 while True:88 # Write every second, notify every 10 seconds.89 i = (i + 1) % 1090 temp.set_temperature(t, notify=i == 0, indicate=False)91 # Random walk the temperature.92 t += random.uniform(-0.5, 0.5)93 time.sleep_ms(1000)
The example code shown above creates a Bluetooth® Low Energy service and characteristics according to the Bluetooth® LE standard for transmitting an emulated temperature value.
- The code begins by importing all the necessary modules and defining the Bluetooth® Low Energy service and characteristics for an environment-sensing application.
Description | ID |
---|---|
Environmental Sensing Service | 181A |
Temperature Characteristic | 2A6E |
Then sets up the Bluetooth® Low Energy service and characteristics; and begins advertising the defined Bluetooth® Low Energy service.
A Bluetooth® Low Energy connection is constantly verified; when a central device connects to the Nicla Vision, its built-in LED is turned on blue. The code then enters into a loop that constantly emulates a temperature reading.
It also prints it to the Serial Monitor and transmits it to the central device over the defined Bluetooth® Low Energy characteristic.
With Arduino IDE
For this Bluetooth® LE application example, we are going to monitor the Nicla Vision IMU temperature sensor. Below you will find the complete sketch.
1#include <ArduinoBLE.h>2#include <Arduino_LSM6DSOX.h>3// Bluetooth® Low Energy Environmental Sensing service4BLEService environmentService("181A");5// Bluetooth® Low Energy Temperature Characteristic6BLEIntCharacteristic temperatureVal("2A6E", // standard 16-bit characteristic UUID7 BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes8int oldTemperature = 0; // last temperature reading from analog input9
10long previousMillis = 0; // last time the temperature was checked, in ms11void blePeripheralDisconnectHandler(BLEDevice central) {12 digitalWrite(LEDR, LOW); // turn on red LED13 digitalWrite(LEDG, HIGH);14 digitalWrite(LEDB, HIGH);15 Serial.println("Device disconnected.");16}17void blePeripheralConnectHandler(BLEDevice central) {18 digitalWrite(LEDB, LOW); // turn on blue LED19 digitalWrite(LEDR, HIGH);20 digitalWrite(LEDG, HIGH);21 Serial.println("Device connected.");22}23void setup() {24 Serial.begin(9600); // initialize serial communication25 while (!Serial)26 ;27
28 pinMode(LEDR, OUTPUT);29 pinMode(LEDG, OUTPUT);30 pinMode(LEDB, OUTPUT);31 // turn off all the LEDs32 digitalWrite(LEDR, HIGH);33 digitalWrite(LEDG, HIGH);34 digitalWrite(LEDB, HIGH);35
36 if (!IMU.begin()) {37 Serial.println("Failed to initialize IMU!");38 while (1)39 ;40 }41
42 // begin initialization43 if (!BLE.begin()) {44 Serial.println("starting BLE failed!");45 while (1)46 ;47 }48 /* Set a local name for the Bluetooth® Low Energy device49 This name will appear in advertising packets50 and can be used by remote devices to identify this Bluetooth® Low Energy device51 The name can be changed but maybe be truncated based on space left in advertisement packet52 */53 BLE.setLocalName("Temperature Sensor");54 BLE.setAdvertisedService(environmentService); // add the service UUID55 environmentService.addCharacteristic(temperatureVal); // add the temperature characteristic56 BLE.addService(environmentService); // Add the environment sensing service57 temperatureVal.writeValue(oldTemperature); // set initial value for this characteristic58 BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler); // handler that fires when BLE is disconnected59 BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler); // handler that fires when BLE is disconnected60 /* Start advertising Bluetooth® Low Energy. It will start continuously transmitting Bluetooth® Low Energy61 advertising packets and will be visible to remote Bluetooth® Low Energy central devices62 until it receives a new connection */63 // start advertising64 BLE.advertise();65 Serial.println("Bluetooth® device active, waiting for connections...");66}67void loop() {68 // wait for a Bluetooth® Low Energy central69 BLEDevice central = BLE.central();70 // if a central is connected to the peripheral:71 if (central) {72 Serial.print("Connected to central: ");73 // print the central's BT address:74 Serial.println(central.address());75 // check the temperature every 200ms76 // while the central is connected:77 while (central.connected()) {78 long currentMillis = millis();79 // if 200ms have passed, check the temperature:80 if (currentMillis - previousMillis >= 200) {81 previousMillis = currentMillis;82 updateTemperature();83 }84 }85 Serial.print("Disconnected from central: ");86 Serial.println(central.address());87 }88}89void updateTemperature() {90 /* Read the temperature*/91 int temperature = 0; // this command return the battery percentage92 if (IMU.temperatureAvailable()) {93 IMU.readTemperature(temperature);94 }95
96 if (temperature != oldTemperature) { // if the battery level has changed97 Serial.print("Temperature is: "); // print it98 Serial.print(temperature);99 Serial.println(" °C");100 temperatureVal.writeValue(temperature * 100); // and update the battery level characteristic101 oldTemperature = temperature; // save the level for next comparison102 }103 delay(1000);104}
The example code shown above creates a Bluetooth® Low Energy service and characteristics according to the Bluetooth® LE standard for transmitting temperature value read by Nicla Vision IMU IC.
- The code begins by importing all the necessary libraries and defining the Bluetooth® Low Energy service and characteristics for an environment sensing application.
Description | ID |
---|---|
Environmental Sensing Service | 181A |
Temperature Characteristic | 2A6E |
In the
function, the code initializes the Nicla Vision board and sets up the Bluetooth® Low Energy service and characteristics; then, it begins advertising the defined Bluetooth® Low Energy service.setup()
A Bluetooth® Low Energy connection is constantly verified in the
function; when a central device connects to the Nicla Vision, its built-in LED is turned on blue. The code then enters into a loop that constantly reads the IMU temperature sensor. It also prints it to the Serial Monitor and transmits it to the central device over the defined Bluetooth® Low Energy characteristic.loop()
Wi-Fi®
The Nicla Vision onboard IEEE802.11 b/g/n Wi-Fi® interface can be operated as an access point (AP), station (STA) or dual-mode simultaneous AP/STA. It supports a maximum transfer rate of 65 Mbps.
With OpenMV
The example code below shows how to get the current time using NTP.
1import network2import socket3import struct4import time5
6SSID = "" # Network SSID7KEY = "" # Network key8
9TIMESTAMP = 220898880010
11if time.gmtime(0)[0] == 2000:12 TIMESTAMP += 94668480013
14# Init wlan module and connect to network15print("Trying to connect... (This may take a while)...")16wlan = network.WLAN(network.STA_IF)17wlan.active(True)18wlan.connect(SSID, KEY)19
20while not wlan.isconnected():21 print('Trying to connect to "{:s}"...'.format(SSID))22 time.sleep_ms(1000)23
24# We should have a valid IP now via DHCP25print("WiFi Connected ", wlan.ifconfig())26
27# Create new socket28client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)29
30# Get addr info via DNS31addr = socket.getaddrinfo("pool.ntp.org", 123)[0][4]32
33# Send query34client.sendto("\x1b" + 47 * "\0", addr)35data, address = client.recvfrom(1024)36
37# Print time38t = struct.unpack(">IIIIIIIIIIII", data)[10] - TIMESTAMP39print("Year:%d Month:%d Day:%d Time: %d:%d:%d" % (time.localtime(t)[0:6]))
Make sure to enter your Wi-Fi® credentials on the
SSID
and KEY
variables and run the script from the OpenMV IDE.The current time and date will be printed on the IDE serial monitor.
If you want to learn more about using Nicla Vision's Wi-Fi® with OpenMV, explore the built-in examples on File > Examples > WiFi.
With Arduino IDE
The example code below shows how to get the current time using NTP.
1#include <NTPClient.h> //http://librarymanager/All#NTPClient2#include <WiFi.h> 3#include <WiFiUdp.h>4
5const char *ssid = "";6const char *password = "";7
8WiFiUDP ntpUDP;9
10NTPClient timeClient(ntpUDP);11
12void setup() {13 Serial.begin(115200);14
15 WiFi.begin(ssid, password);16
17 while (WiFi.status() != WL_CONNECTED) {18 delay(500);19 Serial.print(".");20 }21
22 timeClient.begin();23}24
25void loop() {26 timeClient.update();27
28 time_t nowEpoch = timeClient.getEpochTime();29 struct tm *nowStruct = gmtime(&nowEpoch);30 int year = nowStruct->tm_year + 1900;31 int day = nowStruct->tm_mday;32
33 Serial.print("Year: ");34 Serial.print(year);35 Serial.print(" Day: ");36 Serial.print(day);37 Serial.print(" Time: ");38 Serial.println(timeClient.getFormattedTime());39
40 delay(1000);41}
Make sure to enter your Wi-Fi® credentials on the
*ssid
and *password
variables and upload the code from the Arduino IDE.The current time and date will be printed on the IDE serial monitor.
If your Nicla Vision reports an error when trying to connect to Wi-Fi® saying Failed to mount the filesystem containing the WiFi firmware, follow the next steps.
In the Arduino IDE navigate to File > Examples > STM32H747_System > WiFiFirmwareUpdater, upload this code to your Nicla Vision and wait for the update. The progress can be followed in the Serial Monitor.
ESLOV Connector
The Nicla Vision board features an onboard ESLOV connector meant as an extension of the I2C communication bus. This connector simplifies the communication between the Nicla Vision and various sensors, actuators, and other modules without soldering or wiring.
The ESLOV connector is a small 5-pin connector with a 1.00 mm pitch; the mechanical details of the connector can be found in the connector's datasheet.
The pin layout of the ESLOV connector is the following:
- VCC_IN (5V input)
- INT
- SCL
- SDA
- GND
Arduino Cloud
Leveraging the Nicla Vision's Wi-Fi® connectivity we can develop Smart IoT projects using the Arduino Cloud.
By using the Arduino Cloud, you can, for example, monitor your Nicla's inputs and sensors, control your device's built-in LEDs remotely, and update your device's firmware OTA.
In case it is the first time you are using the Arduino Cloud:
- You need an account. If you do not have an account, create one for free here.
- To use the Arduino Web Editor or Arduino Cloud, the Arduino Create Agent must be running on your computer. You can install the Arduino Create Agent here.
Let's walk through a step-by-step demonstration of how to use a Nicla Vision with the Arduino Cloud.
Log in to your Arduino Cloud account; you should see the following (without any "Thing" created):
First, provision your Nicla Vision on your Arduino Cloud space. To do this, navigate to Devices and then click on the ADD button:
The Setup Device pop-up window will appear. Navigate into AUTOMATIC and select the Arduino board option:
After a while, your Nicla Vision should be discovered by the Arduino Cloud, as shown below:
Click the CONFIGURE button, give your device a name, and your Nicla Vision will be configured to communicate securely with the Arduino Cloud; this process can take a while.
Once your Nicla Vision has been configured, let's create a "Thing" to test the connection between your board and the Arduino Cloud. Navigate into Things and select the CREATE button; give your thing a name.
Navigate into Associate Device and click the Select Device button. Select your Nicla Vision and associate it with your "Thing." Then, navigate into Network and click the Configure button; enter your network credentials.
The project is ready to add variables to your "Thing"; navigate into Cloud Variables and click the ADD VARIABLE button.
Add one variable with the following characteristics:
- Name:
led
- Variable type:
boolean
- Variable permission:
Read & Write
- Variable update policy:
On change
Now, navigate into Dashboards and select the CREATE button; this will create a new dashboard and give your dashboard a name.
Add the following widgets to your dashboard:
- Switch: Name the widget Switch and link it to the
variable you created before.led
- LED: Name the widget LED and link it to the
variable you created before.led
- Sticky Note: Give context to your dashboard with a descriptive title (optional).
Your dashboard should look like the following:
Go back to your Things and open the "Thing" you created. In the "Thing" setup page, navigate into Sketch, where you should see the online editor.
In the generated sketch, define
LEDR
pin as an output in the setup()
function:1void setup() {2 // Initialize serial and wait for port to open:3 Serial.begin(9600);4 // This delay gives the chance to wait for a Serial Monitor without blocking if none is found5 delay(1500); 6 7 // Nicla Vision's red LED macro is LEDR8 pinMode(LEDR, OUTPUT);9 // As they turn on with "LOW", initially turn it off.10 digitalWrite(LEDR, HIGH);11 12 // Defined in thingProperties.h13 initProperties();14
15 // Connect to Arduino Cloud16 ArduinoCloud.begin(ArduinoIoTPreferredConnection);17 18 /*19 The following function allows you to obtain more information20 related to the state of network and IoT Cloud connection and errors21 the higher number the more granular information you’ll get.22 The default is 0 (only errors).23 Maximum is 424 */25 setDebugMessageLevel(2);26 ArduinoCloud.printDebugInfo();27}
In the
onLedChange()
function, which was generated automatically by the Arduino Cloud when the variable led
was created, you must associate the onboard red LED state with the led
variable:1/*2 Since Led is READ_WRITE variable, onLedChange() is3 executed every time a new value is received from IoT Cloud.4*/5void onLedChange() {6 digitalWrite(LEDR, !led);7}
To upload the code to the Nicla Vision from the online editor, click the green Verify button to compile the sketch and check for errors, then click the green Upload button to program the board with the sketch.
Navigate into Dashboards again, your board should connect to the Wi-Fi® network you defined before (you can follow the connection process with the online editor's integrated Serial Monitor). Your board's red LED (LEDR) should light on or off when the position of the switch changes.
Support
If you encounter any issues or have questions while working with the Nicla Vision, we provide various support resources to help you find answers and solutions.
Help Center
Explore our Help Center, which offers a comprehensive collection of articles and guides for the Nicla Vision. The Arduino Help Center is designed to provide in-depth technical assistance and help you make the most of your device.
Forum
Join our community forum to connect with other Nicla Vision users, share your experiences, and ask questions. The forum is an excellent place to learn from others, discuss issues, and discover new ideas and projects related to the Nicla Vision.
Contact Us
Please get in touch with our support team if you need personalized assistance or have questions not covered by the help and support resources described before. We're happy to help you with any issues or inquiries about the Nicla Vision.
Suggest changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything wrong, you can edit this page here.
License
The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike 4.0 license.