Nano 33 BLE Sense Python Guide

Discover how to access the features on the Nano 33 BLE Sense using Python scripts.

The Nano 33 BLE Sense
The Nano 33 BLE Sense

The Nano 33 BLE Sense board board can be programmed using the popular Python programming language. More specifically, it supports OpenMV's fork of MicroPython, where MicroPython is an implementation of the Python language, designed to run on microcontrollers. In this article, you will find a lot of sample scripts that will work directly with your Nano 33 BLE Sense, such as general GPIO control, reading onboard sensors and Wi-Fi/BLE communication!

  • If you want to read more about Arduino & Python, you can visit the Python with Arduino article. Here you will find a lot of useful examples, such as how to use delays, interrupts, reading pins and more general functions.

Hardware & Software Needed

This guide does not cover the installation of OpenMV and MicroPython on your board. Please refer to Getting started with OpenMV and Nano 33 BLE Sense for a detailed guide.

API

Below you will find a lot of useful examples that can be loaded to your Nano 33 BLE Sense board. Many of these examples were extracted from the OpenMV repository, where you can find many useful examples for other boards as well.

In this article, you will only find examples for the Nano 33 BLE Sense board. For more information on how to use delays, read and write to pins, please refer to the Python with Arduino main article.

Pin Control

The pinout for the Nano 33 BLE Sense and the NRF52840 microcontroller varies greatly. For example, if we are to use

D2
according to the Arduino pinout, we would actually need to use pin 43.

1# Defining "D2" on the Nano 33 BLE Sense
2p0 = Pin(43, Pin.OUT)

In the MicroPython port of the Nano 33 BLE Sense board, the pinout is the same as the Nordic NRF52840 (the microcontroller). You will find a pin map below this section that explains how to address the different pins.

Pin Map

Before you start using the board's pins, it might be a good idea to check out the table below to understand the relationship between Arduino's pinout and the NRF52840's pinout.

ArduinonRF52840
TX35
RX42
D243
D344
D447
D545
D646
D723
D821
D927
D1034
D1133
D1240
D1313
D14/A04
D15/A15
D16/A230
D17/A329
D18/A431
D19/A52
D20/A628
D21/A73

Analog Pins

To read the analog pins on the Nano BLE Sense, we can choose from the following pins:

  • A0 -
    4
  • A1 -
    5
  • A2 -
    30
  • A3 -
    29
  • A4 -
    31
  • A5 -
    2
  • A6 -
    28
  • A7 -
    3

To define them, we need to import the

machine
module, and define the pin as follows:

1import machine
2
3adc_pin = machine.Pin(29)
4adc = machine.ADC(adc_pin)

To read the analog pin, simply use:

1reading = adc.read_u16() #16-bit resolution (0-65535)

The below script will read the

A3
pin on the Arduino Nano BLE Sense and print the value in the terminal.

1import machine
2import time
3
4adc_pin = machine.Pin(29) # A3
5adc = machine.ADC(adc_pin)
6
7while True:
8 reading = adc.read_u16()
9 print("ADC: ",reading)
10 time.sleep_ms(500)

LED Control

There are 3 different LEDs that can be accessed on the Nano BLE Sense: RGB, the built-in LED and the power LED.

They can be accessed by importing the

LED
module, where the RGB and built-in LED can be accessed.

1from board import LED
2
3led_red = LED(1) # red LED
4led_green = LED(2) # green LED
5led_blue = LED(3) # blue LED
6led_builtin = LED(4) # classic built-in LED (also accessible through pin 13)

To access the power LED we need to import the

Pin
module.

1from machine import Pin
2
3led_pwr = Pin(41, Pin.OUT)

RGB

Blink all RGB lights every 0.25 seconds.

1from board import LED
2import time
3
4led_red = LED(1)
5led_green = LED(2)
6led_blue = LED(3)
7
8while (True):
9
10 # Turn on LEDs
11 led_red.on()
12 led_green.on()
13 led_blue.on()
14
15 # Wait 0.25 seconds
16 time.sleep_ms(250)
17
18 # Turn off LEDs
19 led_red.off()
20 led_green.off()
21 led_blue.off()
22
23 # Wait 0.25 seconds
24 time.sleep_ms(250)

Built-in LED

The classic blink example! Blink the built-in LED every 0.25 seconds.

1from board import LED
2import time
3
4led_builtin = LED(4)
5
6while (True):
7
8 # Turn on LED
9 led_builtin.on()
10
11 # Wait 0.25 seconds
12 time.sleep_ms(250)
13
14 # Turn off LED
15 led_builtin.off()
16
17 # Wait 0.25 seconds
18 time.sleep_ms(250)

Sensors

There are several sensors onboard the Nano 33 BLE Sense. The scripts below can be used to access the data from each of them.

IMU (LSM9DS1)

Access the

accelerometer
,
magnetometer
, and
gyroscope
data from the LSM9DS1 IMU module.

1import time
2import lsm9ds1
3from machine import Pin, I2C
4
5bus = I2C(1, scl=Pin(15), sda=Pin(14))
6lsm = lsm9ds1.LSM9DS1(bus)
7
8while (True):
9 #for g,a in lsm.iter_accel_gyro(): print(g,a) # using fifo
10 print('Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_accel()))
11 print('Magnetometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_magnet()))
12 print('Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_gyro()))
13 print("")
14 time.sleep_ms(500)

Temperature & Humidity (HTS221)

Access the

temperature
&
humidity
values from the HTS221 sensor.

1import time
2import hts221
3from machine import Pin, I2C
4
5bus = I2C(1, scl=Pin(15), sda=Pin(14))
6hts = hts221.HTS221(bus)
7
8while (True):
9 rH = hts.humidity()
10 temp = hts.temperature()
11 print ("rH: %.2f%% T: %.2fC" %(rH, temp))
12 time.sleep_ms(100)

Pressure (LPS22)

Access the

pressure
values from the LPS22 sensor.

1import time
2import lps22h
3from machine import Pin, I2C
4
5bus = I2C(1, scl=Pin(15), sda=Pin(14))
6lps = lps22h.LPS22H(bus)
7
8while (True):
9 pressure = lps.pressure()
10 temperature = lps.temperature()
11 print("Pressure: %.2f hPa Temperature: %.2f C"%(pressure, temperature))
12 time.sleep_ms(100)

Ambient Light (APDS9960)

Access the

Ambient Light
values from the APDS9960 sensor.

1from time import sleep_ms
2from machine import Pin, I2C
3from apds9960.const import *
4from apds9960 import uAPDS9960 as APDS9960
5
6bus = I2C(1, sda=Pin(13), scl=Pin(14))
7apds = APDS9960(bus)
8
9print("Light Sensor Test")
10print("=================")
11apds.enableLightSensor()
12
13while True:
14 sleep_ms(250)
15 val = apds.readAmbientLight()
16 print("AmbientLight={}".format(val))

Proximity (APDS9960)

Access the

Proximity values
from the APDS9960 sensor.

1from time import sleep_ms
2from machine import Pin, I2C
3
4from apds9960.const import *
5from apds9960 import uAPDS9960 as APDS9960
6
7bus = I2C(1, sda=Pin(13), scl=Pin(14))
8apds = APDS9960(bus)
9
10apds.setProximityIntLowThreshold(50)
11
12print("Proximity Sensor Test")
13print("=====================")
14apds.enableProximitySensor()
15
16while True:
17 sleep_ms(250)
18 val = apds.readProximity()
19 print("proximity={}".format(val))

Microphone (MP34DT05)

Below example can be used with OpenMV's frame buffer window (top right corner).

1import image, audio, time
2from ulab import numpy as np
3from ulab import scipy as sp
4
5CHANNELS = 1
6SIZE = 256//(2*CHANNELS)
7
8raw_buf = None
9fb = image.Image(SIZE+50, SIZE, image.RGB565, copy_to_fb=True)
10audio.init(channels=CHANNELS, frequency=16000, gain_db=80, highpass=0.9883)
11
12def audio_callback(buf):
13 # NOTE: do Not call any function that allocates memory.
14 global raw_buf
15 if (raw_buf == None):
16 raw_buf = buf
17
18# Start audio streaming
19audio.start_streaming(audio_callback)
20
21def draw_fft(img, fft_buf):
22 fft_buf = (fft_buf / max(fft_buf)) * SIZE
23 fft_buf = np.log10(fft_buf + 1) * 20
24 color = (0xFF, 0x0F, 0x00)
25 for i in range(0, SIZE):
26 img.draw_line(i, SIZE, i, SIZE-int(fft_buf[i]), color, 1)
27
28def draw_audio_bar(img, level, offset):
29 blk_size = SIZE//10
30 color = (0xFF, 0x00, 0xF0)
31 blk_space = (blk_size//4)
32 for i in range(0, int(round(level/10))):
33 fb.draw_rectangle(SIZE+offset, SIZE - ((i+1)*blk_size) + blk_space, 20, blk_size - blk_space, color, 1, True)
34
35while (True):
36 if (raw_buf != None):
37 pcm_buf = np.frombuffer(raw_buf, dtype=np.int16)
38 raw_buf = None
39
40 if CHANNELS == 1:
41 fft_buf = sp.signal.spectrogram(pcm_buf)
42 l_lvl = int((np.mean(abs(pcm_buf[1::2])) / 32768)*100)
43 else:
44 fft_buf = sp.signal.spectrogram(pcm_buf[0::2])
45 l_lvl = int((np.mean(abs(pcm_buf[1::2])) / 32768)*100)
46 r_lvl = int((np.mean(abs(pcm_buf[0::2])) / 32768)*100)
47
48 fb.clear()
49 draw_fft(fb, fft_buf)
50 draw_audio_bar(fb, l_lvl, 0)
51 if CHANNELS == 2:
52 draw_audio_bar(fb, r_lvl, 25)
53 fb.flush()
54
55# Stop streaming
56audio.stop_streaming()

Bluetooth® Low Energy

This example allows us to connect to our board via our phone, and control the built-in LED. We recommend using the nRF Connect applications.

After loading the script below, your board should be listed as "Nano 33 BLE Sense" in the list of available devices. You need to pair in order to control the built-in LED.

1# Use nRF Connect from App store, connect to the Nano and write 1/0 to control the LED.
2
3import time
4from board import LED
5from ubluepy import Service, Characteristic, UUID, Peripheral, constants
6
7def event_handler(id, handle, data):
8 global periph
9 global service
10 if id == constants.EVT_GAP_CONNECTED:
11 pass
12 elif id == constants.EVT_GAP_DISCONNECTED:
13 # restart advertisement
14 periph.advertise(device_name="Nano 33 BLE Sense", services=[service])
15 elif id == constants.EVT_GATTS_WRITE:
16 LED(1).on() if int(data[0]) else LED(1).off()
17
18# start off with LED(1) off
19LED(1).off()
20
21notif_enabled = False
22uuid_service = UUID("0x1523")
23uuid_led = UUID("0x1525")
24
25service = Service(uuid_service)
26char_led = Characteristic(uuid_led, props=Characteristic.PROP_WRITE)
27service.addCharacteristic(char_led)
28
29periph = Peripheral()
30periph.addService(service)
31periph.setConnectionHandler(event_handler)
32periph.advertise(device_name="Nano 33 BLE Sense", services=[service])
33
34while (True):
35 time.sleep_ms(500)

Summary

In this article we have gone through a selection of scripts that will help you control your Nano BLE Sense board, via the OpenMV IDE. Feel free to check out our Python with Arduino boards article, where you can find guides to other boards, useful links to learn Python and more.

Contribute to Arduino

Join the community and suggest improvements to this article via GitHub. Make sure to read out contribution policy before making your pull request.

Missing something?

Check out our store and get what you need to follow this tutorial.

Suggest Changes

The content on docs.arduino.cc is facilitated through a public GitHub repository. You can read more on how to contribute in the contribution policy.