Introduction
All the code written for this article is available at arduino-nicla-sense-me directory from arduino-projects GitLab repository.
I wrote many code samples with the aim of allowing a better readability and to reduce the amount of code snippets along the article. Moreover, I linked the different subdirectories where I wrote the actual code.
Feel free to make pull requests to the repository if you find something to improve or fix.
Main Features
The Arduino® Nicla Sense ME is the smallest form factor yet. It features industrial grade sensors and Bluetooth® Low Energy connectivity.
BHI260AP
AI smart sensor hub has 6-axis
IMU to detect activities performed over the board:
3-axis
accelerometer3-axis
gyroscope
It is powered by a 32-bit
Synopsys DesignWare ARC™ EM4™ CPU.
BMP390
High performance digital pressure sensor: 300
to 1250 hPa
with low drift.
BMM150
Low noise magnetometer with ranges of:
±1300μT
in x and y axes±2500μT
in z axis
BME688
Environmental sensor that mainly measures pressure, humidity and temperature. The onboard smart gas sensor can also determinate the IAQ (Index Air Quality) by detecting a broad range of gases, as you’ll see in the sections below.
Tech Specs
The board is powered by Cortex-M4 nRF52832 microcontroller.
It provides 64kB
of SRAM and 512kB
of flash memory. Moreover, a couple of MX25R1635FZUIH0, gives 2MB
for data logging and 2MB
storage (for BHI260AP).
The processor’s clock speed is 64MHz
.
BLE connectivity is ensured by ANNA B112 Bluetooth® module, which also ensure RTC. While wired communication is given by UART, I2C and SPI protocols.
The microcontroller operates at 1.8V
voltage translated to 3.3V
on external pins.
The board can be charged with a Li-ion/Li-Po single cell (3.7V
) using the JST battery connector (3-pin 1.2 mm
pitch).
Each I/O pin drains up to 4.7 mA
DC current.
Lastly, the board weigh 2g
with a size of 22.86 mm x 22.86 mm
.
Installation
The Nicla uses the Arduino Mbed OS Nicla Boards core.
Take a look at those tutorials to properly install the library:
Pins & RGB LED
Analog pins
There are 2 analog pins, A0
and A1
, which can be controlled through analogRead() function.
PWM Pins
There are 12 PWM (Pulse Width Modulation) pins. Some of them are shared:
Digital Pins
There are 10 digital pins: the 2 analog pins can also be used as digital pins.
The configuration is usually made in setup()
function:
pinMode(pin, INPUT); //configured as an input
pinMode(pin, OUTPUT); //configured as an output
pinMode(pin, INPUT_PULLUP); //uses an internal pull up resistor
bool state = digitalRead(pin); // read the state of a digital pin
digitalWrite(pin, HIGH); // write a state to a digital pin
int value = 128;
analogWrite(pin, value); // write a value from 0 to 255 to a PWM pin
RGB LED
The built-in RGB LED can be used as a feedback component for application where’s not possible to attach a Serial Monitor.
Take a look at built-in-RGB-LED directory to get code samples.
Please Note: Nicla_System header is required to use the RGB LED.
Sensors
Sensor Classes
Sensor
class handles all the sensors which have a single value to be read (also event sensors, like the step detector).
It provides the sensor data through the float property value
.
SensorOrientation
class handles sensors with the Euler format.
It allows you to read the pitch
, roll
and heading
properties.
SensorXYZ
class handles sensors with the XYZ format.
You can access x
, y
and z
properties.
SensorQuaternion
class handle sensors with the quaternion format.
It’s used to calculate rotation vector, game rotation vector and geomagnetic rotation vector.
You can access x
, y
, z
and w
properties.
SensorActivity
class to handle sensors with the activity format.
The activity is encoded as ID
retrieved from the value
property: use getActivity()
to get a human-readable version of the activity.
SensorBSEC
where BSEC stands for Bosch Sensortec Environmental Cluster.
Access the air quality index (IAQ) level on top of other environmental parameters:
Function | Description | Data type |
---|---|---|
iaq() | IAQ value for regular use case | unsigned 16 bit |
iaq_s() | IAQ value for stationary use cases | unsigned 16 bit |
b_voc_eq() | breath VOC equivalent (ppm ) | float |
co2_eq() | CO2 equivalent (ppm ) [400,] | unsigned 32 bit |
comp_t() | compensated temperature (Celsius) | float |
comp_h() | compensated humidity | float |
comp_g() | compensated gas resistance (Ohms) | unsigned 32 bit |
accuracy() | accuracy level: [0-3] | unsigned 8 bit |
Sensor IDs
Each sensor has a unique identifier, as you can see in the table below. You can also run a sketch that prints them all on the Serial Monitor: File > Examples > Arduino_BHY2 > ShowSensorList.
ID | Description | SENSOR_ID MACRO | Class |
---|---|---|---|
1 | Accelerometer passthrough | SENSOR_ID_ACC_PASS | SensorXYZ |
3 | Accelerometer uncalibrated | SENSOR_ID_ACC_RAW | SensorXYZ |
4 | Accelerometer corrected | SENSOR_ID_ACC | SensorXYZ |
5 | Accelerometer offset | SENSOR_ID_ACC_BIAS | SensorXYZ |
6 | Accelerometer corrected wake up | SENSOR_ID_ACC_WU | SensorXYZ |
7 | Accelerometer uncalibrated wake up | SENSOR_ID_ACC_RAW_WU | SensorXYZ |
10 | Gyroscope passthrough | SENSOR_ID_GYRO_PASS | SensorXYZ |
12 | Gyroscope uncalibrated | SENSOR_ID_GYRO_RAW | SensorXYZ |
13 | Gyroscope corrected | SENSOR_ID_GYRO | SensorXYZ |
14 | Gyroscope offset | SENSOR_ID_GYRO_BIAS | SensorXYZ |
15 | Gyroscope wake up | SENSOR_ID_GYRO_WU | SensorXYZ |
16 | Gyroscope uncalibrated wake up | SENSOR_ID_GYRO_RAW_WU | SensorXYZ |
19 | Magnetometer passthrough | SENSOR_ID_MAG_PASS | SensorXYZ |
21 | Magnetometer uncalibrated | SENSOR_ID_MAG_RAW | SensorXYZ |
22 | Magnetometer corrected | SENSOR_ID_MAG | SensorXYZ |
23 | Magnetometer offset | SENSOR_ID_MAG_BIAS | SensorXYZ |
24 | Magnetometer wake up | SENSOR_ID_MAG_WU | SensorXYZ |
25 | Magnetometer uncalibrated wake up | SENSOR_ID_MAG_RAW_WU | SensorXYZ |
28 | Gravity vector | SENSOR_ID_GRA | SensorXYZ |
29 | Gravity vector wake up | SENSOR_ID_GRA_WU | SensorXYZ |
31 | Linear acceleration | SENSOR_ID_LACC | SensorXYZ |
32 | Linear acceleration wake up | SENSOR_ID_LACC_WU | SensorXYZ |
34 | Rotation vector | SENSOR_ID_RV | SensorQuaternion |
35 | Rotation vector wake up | SENSOR_ID_RV_WU | SensorQuaternion |
37 | Game rotation vector | SENSOR_ID_GAMERV | SensorQuaternion |
38 | Game rotation vector wake up | SENSOR_ID_GAMERV_WU | SensorQuaternion |
40 | Geomagnetic rotation vector | SENSOR_ID_GEORV | SensorQuaternion |
41 | Geomagnetic rotation vector wake up | SENSOR_ID_GEORV_WU | SensorQuaternion |
43 | Orientation | SENSOR_ID_ORI | SensorOrientation |
44 | Orientation wake up | SENSOR_ID_ORI_WU | SensorOrientation |
48 | Tilt detector | SENSOR_ID_TILT_DETECTOR | Sensor |
50 | Step detector | SENSOR_ID_STD | Sensor |
52 | Step counter | SENSOR_ID_STC | Sensor |
53 | Step counter wake up | SENSOR_ID_STC_WU | Sensor |
55 | Significant motion | SENSOR_ID_SIG | Sensor |
57 | Wake gesture | SENSOR_ID_WAKE_GESTURE | Sensor |
59 | Glance gesture | SENSOR_ID_GLANCE_GESTURE | Sensor |
61 | Pickup gesture | SENSOR_ID_PICKUP_GESTURE | Sensor |
63 | Activity recognition | SENSOR_ID_AR | SensorActivity |
67 | Wrist tilt gesture | SENSOR_ID_WRIST_TILT_GESTURE | Sensor |
69 | Device orientation | SENSOR_ID_DEVICE_ORI | SensorOrientation |
70 | Device orientation wake up | SENSOR_ID_DEVICE_ORI_WU | Sensor |
75 | Stationary detect | SENSOR_ID_STATIONARY_DET | Sensor |
77 | Motion detect | SENSOR_ID_MOTION_DET | Sensor |
91 | Accelerometer offset wake up | SENSOR_ID_ACC_BIAS_WU | SensorXYZ |
92 | Gyroscope offset wake up | SENSOR_ID_GYRO_BIAS_WU | SensorXYZ |
93 | Magnetometer offset wake up | SENSOR_ID_MAG_BIAS_WU | SensorXYZ |
94 | Step detector wake up | SENSOR_ID_STD_WU | Sensor |
115 | BSEC data | SENSOR_ID_BSEC | SensorBSEC |
128 | Temperature | SENSOR_ID_TEMP | Sensor |
129 | Barometer | SENSOR_ID_BARO | Sensor |
130 | Humidity | SENSOR_ID_HUM | Sensor |
131 | Gas | SENSOR_ID_GAS | Sensor |
132 | Temperature wake up | SENSOR_ID_TEMP_WU | Sensor |
133 | Barometer wake up | SENSOR_ID_BARO_WU | Sensor |
134 | Humidity wake up | SENSOR_ID_HUM_WU | Sensor |
135 | Gas wake up | SENSOR_ID_GAS_WU | Sensor |
136 | Hardware Step counter | SENSOR_ID_STC_HW | Sensor |
137 | Hardware Step detector | SENSOR_ID_STD_HW | Sensor |
138 | Hardware Significant motion | SENSOR_ID_SIG_HW | Sensor |
139 | Hardware Step counter wake up | SENSOR_ID_STC_HW_WU | Sensor |
140 | Hardware Step detector wake up | SENSOR_ID_STD_HW_WU | Sensor |
141 | Hardware Significant motion wake up | SENSOR_ID_SIG_HW_WU | Sensor |
142 | Any motion | SENSOR_ID_ANY_MOTION | Sensor |
143 | Any motion wake up | SENSOR_ID_ANY_MOTION_WU | Sensor |
Using the table above, instantiate a sensor object and retrieve the data:
SensorXYZ mySensor(SENSOR_ID_MAG); // declare Magnetometer corrected sensor
mySensor.begin() // start pulling the sensor inside the setup()
BHY2.update(); // this should be continuously polled inside loop()
Serial.print(mySensor.x()); // print the x sensor value
Serial.print(mySensor.y()); // print the y sensor value
Serial.print(mySensor.z()); // print the z sensor value
Take a look at those sensors’ subdirectories:
- sensor-activity
- sensor-bsec
- sensor
- sensors-hardware
- sensors-orientation
- sensors-quaternion
- sensors-xyz
Communication
You need to install both Arduino_BHY2 and Arduino_BHY2Host libraries or nicla-sense-me-fw, which include both of them. In the Arduino IDE, select Tools > Manage Libraries… and search for them.
Or you can clone the whole repository like so:
cd ~/Arduino/libraries
git clone https://github.com/arduino/nicla-sense-me-fw
On-board sensors can be read in Standalone mode using the predefined sensor classes. Sensors can also be accessed by external boards with Arduino_BHY2Host library using the following protocols:
- BLE
- UART using an ESLOV cable
Please Note: The Serial Monitor’s baud rate for the Nicla Sense ME is usually 115200
.
BHY tool
Install Go language first, then build bhy
tool binaries.
cd ~/Arduino/libraries/nicla-sense-me-fw/tools/bhy-controller/src/
go build
Bluetooth Low Energy
BLE Standalone
The Nicla Sense ME can communicate in standalone mode using ArduinoBLE library.
Take a look at custom_UUID.ino example sketch from arduino-projects GitLab repository.
BLE from Host board
On the Nicla, upload App.ino sketch.
On the host board, include Arduino_BHY2Host library and configure setup()
function as follows:
#include "Arduino_BHY2Host.h"
void setup() {
Serial.begin(115200);
BHY2Host.begin(false, NICLA_VIA_BLE);
}
void loop() {
static auto lastCheck = millis();
// update function should be continuously polled
BHY2Host.update();
// check sensor values every 'delayTime' milliseconds
if (millis() - lastCheck >= 1000) {
lastCheck = millis();
// add your code here
}
}
Host’s begin()
accepts two parameters: boolean value passthrough
(false
by default) that defines if the data should be passed through the Serial connection or not and NiclaWiring
’s instance niclaConnection
.
Please Note: NiclaWiring
is defined as follows:
enum NiclaWiring {
NICLA_VIA_ESLOV = 0,
NICLA_AS_SHIELD,
NICLA_VIA_BLE
};
From the host board, call and use the sensors as you would do from the Nicla. Examples are placed in BHY2-Host-tests directory from arduino-projects GitLab repository.
WebBLE
Make sure that Web Bluetooth® Low Energy is both supported and enabled. Take care of check the browser compatibility with WebBLE. In Google Chrome: go to chrome://flags and enable both “Experimental Web Platform features” and “Web Bluetooth”.
Once App.ino is uploaded into the Nicla, use the bhy
script to interact with sensors.
cd ~/Arduino/libraries/nicla-sense-me-fw/tools/bhy-controller/src
# start the webserver
./bhy webserver
When the server has started, open the landing page from localhost:8000. Click on “Open sensor page”. Then click the “Connect” button and pair your computer with the Nicla Sense ME board.
Once connected, the page will allow to see all sensors’ data.
ESLOV cable
Once App.ino is uploaded into the Nicla, connect it to the host board using the ESVOL cable. On the host board, upload Passthrough.ino sketch.
You can disconnect the Nicla Sense ME from the USB cable: it’s powered through the ESLOV connection.
After you upload the sketch, a separate serial port will be exposed for the host board:
- debugging (for example
/dev/ttyACM0
) - serial communication for getting the sensor data (for example
/dev/ttyACM1
)
Assuming the host board has /dev/ttyACM1
as second port.
# move to BHY source directory
cd ~/Arduino/libraries/nicla-sense-me-fw/tools/bhy-controller/src
# list available serial ports
./bhy list
# using an Arduino MKR WiFi 1010 as host board, I got this output
Found port: /dev/ttyACM0
USB ID 2341:8054
USB serial 3D2454A550534D53302E3120FF1932223D2454A550534D53302E3120FF193222
Found port: /dev/ttyACM1
USB ID 2341:8054
USB serial 3D2454A550534D53302E3120FF1932223D2454A550534D53302E3120FF193222
The help messages are:
./bhy
./bhy dfu
./bhy sensor
./bhy sensor read
./bhy sensor config
Configure sensor with ID
equal 10
(Gyroscope passthrough) with 1Hz
sample rate and 0ms
of latency.
./bhy sensor config -p /dev/ttyACM1 -sensor 10 -rate 1 -latency 0
# I got this output
Connected - port: /dev/ttyACM1 - baudrate: 115200
Sending configuration: sensor 10 rate 1.000000 latency 0Sent 10 bytes
Sensor configuration correctly sent!
Continuously read sensors data when available:
./bhy sensor read -live -p /dev/ttyACM1
# I got this output
Connected - port: /dev/ttyACM1 - baudrate: 115200
Sensor id: 10 name: GYRO_PASS values: x : 1.000000 y : -3.000000 z : -3.000000
Sensor id: 10 name: GYRO_PASS values: x : 1.000000 y : 0.000000 z : 1.000000
Sensor id: 10 name: GYRO_PASS values: x : 5.000000 y : -7.000000 z : -6.000000
# ...
It will continue until you press Ctrl
+ C
and interrupt the process.
Try to add another sensor, like linear acceleration, that has ID
equal 31
:
./bhy sensor config -p /dev/ttyACM1 -sensor 31 -rate 1 -latency 0
# I got this output
Connected - port: /dev/ttyACM1 - baudrate: 115200
Sending configuration: sensor 31 rate 1.000000 latency 0Sent 10 bytes
Sending configuration: sensor 31 rate 1.000000 latency 0Sent 10 bytes
Sensor configuration correctly sent!
If you now try to read sensors data when available, it will mix sensors output:
./bhy sensor read -live -p /dev/ttyACM1
# I got this output
Connected - port: /dev/ttyACM1 - baudrate: 115200
Sensor id: 10 name: GYRO_PASS values: x : 0.000000 y : 1.000000 z : 4.000000
Sensor id: 10 name: GYRO_PASS values: x : 1.000000 y : 1.000000 z : 3.000000
Sensor id: 31 name: LINEAR_ACC values: x : -2.000000 y : -2.000000 z : 0.000000
# ...
You can disable a sensor by setting its rate
to 0
.
Let’s disable GYRO_PASS
sensor, that has ID
equal 10
:
./bhy sensor config -p /dev/ttyACM1 -sensor 10 -rate 0 -latency 0
# I got this output
Connected - port: /dev/ttyACM1 - baudrate: 115200
Sending configuration: sensor 10 rate 0.000000 latency 0Sent 10 bytes
Sensor configuration correctly sent!
If you now try to read sensors data when available it will only show LINEAR_ACC
values since it’s the only sensor still enabled.
Conclusion
This article is not yet finished: I just scratch the edge of Nicla Sense ME capabilities and I wanted to publish it as a work in progress!
Documentation
Here is the full list of links I used to write this article:
- Datasheets:
- Stores
- Docs:
- Libraries:
- ArduinoCore-mbed
- nicla-sense-me-fw
- Arduino_BHY2 and Arduino_BHY2Host libraries
- ArduinoBLE
- arduino-nicla-sense-me directory from arduino-projects GitLab repository