Development Environment

Overview

Disclaimer: In this class, we aim to setup a development environment that is as isolated as possible without being fully containerized. This is possible via a Git repository that supports:

  • a conda environment for Python, Jupyter, plotting, serial tooling, and TensorFlow
  • a downloaded Arduino CLI binary placed in tools/arduino-cli/
  • repo-local Arduino CLI state so package indexes, downloads, caches, and sketchbook files do not spill into each student’s global machine setup

Setup Environment

Clone repository

First, you are to clone the repository.

1
2
git clone https://github.com/ngo-classes/tinyml.git
cd tinyml

The layout of this repository can be presented as follows.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.
├── .arduino-build-cache/
├── .arduino-data/
├── .arduino-downloads/
├── .arduino-user/
├── arduino-cli.yaml
├── data/
├── environment.yml
├── firmware/
├── models/
├── notebooks/
├── scripts/
└── tools/
    └── arduino-cli/
  • environment.yml: conda environment definition
  • arduino-cli.yaml: Arduino CLI configuration
  • tools/arduino-cli/: where each student places the correct Arduino CLI binary for their OS
  • data/: reserved for datasets; contents ignored by git by default
  • models/: reserved for trained/exported models; contents ignored by git by default
  • .arduino-*: local Arduino CLI package/cache/user state, kept in the repo but ignored by git
Create and activate the conda environment
1
2
3
conda env create -f environment.yml
conda activate tinyml
python -m ipykernel install --user --name tinyml --display-name "Python (tinyml)"
Download and save the Arduino CLI binary

You are to download the latest binary release of Arduino CLI and unzip the downloaded files. Next, place one of the following in tools/arduino-cli/ depending on your system:

  • arduino-cli.exe for Windows
  • arduino-cli for macOS or Linux

That directory is intentionally git-ignored so the binary file is not accidentally committed.

Activate the repo-local Arduino CLI configuration

For macOS/Linux/Git Bash, run the followings:

1
source scripts/activate.sh

For Windows PowerShell, run the followings:

1
2
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\scripts\activate.ps1
Verify setup

For macOS/Linux/Git Bash, run the followings:

1
2
chmod u+x scripts/check-setup.sh
scripts/check-setup.sh
Check results of Arduino CLI activation

For Windows PowerShell, run the followings:

1
.\scripts\check-setup.ps1
Check results of Arduino CLI activation
Setup core libraries
  • This script installs the Arduino Mbed OS Nano Boards core used by the Nano 33 BLE/BLE Sense, plus the course libraries ArduinoBLE, Arduino_BMI270_BMM150, and Harvard_TinyMLx.
  • The script also forces Arduino CLI to use repo-local state via ARDUINO_* variables.

For macOS/Linux/Git Bash, run the followings:

1
2
chmod u+x scripts/bootstrap-arduino.sh
scripts/bootstrap-arduino.sh

For Windows PowerShell, run the followings:

1
.\scripts\bootstrap-arduino.ps1

VSCode and PlatformIO

In this set up, we are using PlatformIO from inside VSCode. Therefore, it is important that you do not need to install PlatformIO Core separately for this workflow; PlatformIO Core is bundled with the VS Code extension and is meant to be used through the PlatformIO IDE Terminal.

Install VSCode

Download and install the official Microsoft build of Visual Studio Code. PlatformIO IDE is built on top of VS Code.

Install PlatformIO

Do the followings in VSCode:

  • On the left sidebar, click the Extensions icon.
Red arrow pointing to the extension side icon
  • In the search box, type PlatformIO.
    • Look for the official PlatformIO IDE extension.
  • Click Install.
Top result of searching for PlatformIO showing the official extension
  • Completely close and reopen VSCode (it might ask for a restart).
  • After restart, the PlatformIO icon will show up on the left activity bar.
Red arrow pointing to PlatformIO icon on the left side activity bar
Verify PlatformIO is using the built-in core
  • Open Settings in VS Code.
  • Search for: platformio use builtin
  • Make sure the box Use a built-in PlatformIO Core is checked.
Settings for platformio use builtin show two checked boxes for Core and Python
Open the PlatformIO CLI inside VSCode
  • Click the PlatformIO ant icon in the left activity bar.
  • Go to Quick Access.
  • Open Miscellaneous.
  • Click PlatformIO Core CLI.
  • Once that terminal opens, test:
1
pio --version
Red arrow pointing to PlatformIO CLI from the icon

For Mac, it is possible that you will need to do some extra PATH setup

1
2
3
4
ln -sf ~/.platformio/penv/bin/platformio ~/.local/bin/platformio
ln -sf ~/.platformio/penv/bin/platformio ~/.local/bin/pio
grep -qxF 'export PATH="$HOME/.local/bin:$PATH"' ~/.zshrc || echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc

First PlatformIO Project

Connect the Nano BLE33
  • Plug the Nano BLE33 into your computer.
  • Open the PlatformIO CLI inside VSCode
  • Run the followings to confirm
1
pio device list
Device list on Mac
List of pio devices with Nano BLE33 is the USB Serial Device
Device list on Windows
List of pio devices with Nano BLE33 is the USB Serial Device
Create your first Arduino project

In VS Code:

  • Click the PlatformIO icon.
  • Click Open under PIO Home to open up the PIO Home tab.
  • Click New Project.
Red boxes showing icons to click
  • Enter a project name: Blink.
  • Choose your board.
  • Uncheck the location box
  • Specific the location of the project directory, which should be the firmware directory of the cloned tinyml repository.
Red boxes showing icons to click
  • Click Finish to create the project.
  • After creation, PlatformIO will generate a standard project structure with:
    • a platformio.ini file
    • two runtime folders, .pio and .vscode.
    • a src/ folder containing aa default main.cpp inside src/
    • empty folders for include, lib, and test.
    • a default .gitignore file.
Build and Deploy
  • Replace the content of main.cpp with the following
    • We will go into the details of this code in the next lecture.
1
2
3
4
5
6
7
8
9
10
11
12
#include <Arduino.h>

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}
  • You should also make sure that the platform.ini file has the following contents
1
2
3
4
5
6
7
[env:nano33ble]
platform = nordicnrf52
board = nano33ble
framework = arduino
lib_deps = 
    arduino-libraries/Arduino_BMI270_BMM150
monitor_speed = 9600
  • To build this project, you are to
    • open the PlatformIO terminal
    • change to the project directory
    • run pio run
  • You might have a warning on LF clock source. That warning can be ignored.
Run results of the Blink project build on a Mac
  • After a successful build, we will need to deploy the built binary to the Nano 33 BLE board.
    • Plug in the board over USB.
    • Run the following command. Use the port identified previously from pio device list.
1
2
# This is for Mac
pio run -t upload --upload-port /dev/cu.usbmodem1201
Upload the built source code to the board

Reading Sensor Data

Create your second Arduino project
  • Setup a second project called Sensors inside firmware directory with the following file contents:

  • platformio.ini:

1
2
3
4
5
6
7
[env:nano33ble]
platform = nordicnrf52
board = nano33ble
framework = arduino
lib_deps = 
    arduino-libraries/Arduino_BMI270_BMM150
monitor_speed = 9600
  • main.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <Arduino.h>
#include <Arduino_BMI270_BMM150.h>

void setup() {
  Serial.begin(9600);

  while (!Serial) {
    ; // wait for serial monitor
  }

  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1) {
      delay(1000);
    }
  }

  Serial.println("Serial ready. Initializing IMU...");
  Serial.println("IMU ready.");
  Serial.println("Ax Ay Az | Gx Gy Gz | Mx My Mz");
}

void loop() {
  float ax, ay, az;
  float gx, gy, gz;
  float mx, my, mz;

  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(ax, ay, az);
  }

  if (IMU.gyroscopeAvailable()) {
    IMU.readGyroscope(gx, gy, gz);
  }

  if (IMU.magneticFieldAvailable()) {
    IMU.readMagneticField(mx, my, mz);
  }
 
  char line[160];

  snprintf(line,sizeof(line),
    "A:%.3f,%.3f,%.3f | G:%.3f,%.3f,%.3f | M:%.3f,%.3f,%.3f",
    ax, ay, az,
    gx, gy, gz,
    mx, my, mz
  );

  Serial.println(line);
  
  delay(200);
}
  • Run and upload.
Python Notebook
  • Open the serial_plot.ipynb and select the tinyml kernel.
  • Follow the notebook instruction to learn how to capture live sensor data from the Nano (that was generated via the previously uploaded Sensors code).