Introduction

The ROHI logo

ROHI (Robonomics Open Hardware Initiative) SDK is a project offering libraries and firmware to build IoT devices powered by Robonomics network - a Web3 cloud platform designed to manage IoT devices and robotics.

SDK Features

The following sections assume basic Rust knowledge. If you're unsure about any language aspects, please refer to the Rust book.

Contributing

ROHI SDK is free and open source. You can find the source code on GitHub, where issues and feature requests can be posted on the issue tracker. The project relies on community contributions to fix bugs and add features - if you'd like to help, please consider opening a pull request.

License

The ROHI SDK source and documentation are released under the Apache v2.0.

Installation

For blazing-fast dependency installation, use the Nix package manager. If you already have Nix, skip to the Nix Way section.

Prerequisites

Before installing the SDK, ensure you have these dependencies:

Rust & Cargo

Use the rustup.rs script for a quick Rust compiler installation.

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

All required Rust components are listed in the rust-toolchain.yml file. Clone the SDK repository.

git clone https://github.com/akagi-dev/rohi-sdk && cd rohi-sdk

And run rustup to install them (remember to add rustup to your PATH if you've just installed it).

rustup toolchain install

Espflash

This tool is required for flashing ESP hardware. The SDK fully supports firmware preparation and launches the flashing process, but the espflash binary must be available in your PATH. For setup details, see the official installation instructions.

Nix Way

Build examples

To verify that all dependencies are installed correctly, try building the ROHI examples package.

cargo build --release -p rohi-examples

Air Quality Terminal

This section assumes you are using the Nix package manager. If you have a different environment, don't worry—most commands will be the same, except you won't need to launch nix-shell first.

If you have successfully built the example, let's understand how it works step by step.

The Altruist board currently has a set of examples for different sensors:

  • altruist-sensor-temp.rs
  • altruist-sensor-press.rs
  • altruist-sensor-pm25.rs

We'll start from altruist-sensor-pm25.rs example, it's based on PM sensors.

Explore the code

no_std

#![no_std]
#![no_main]

The file starts with no_* declarations, which is typical for bare-metal software since there's no operating system or standard library available by default.

Imports

#![allow(unused)]
fn main() {
use esp_backtrace as _;
use log::info;

use embassy_executor::Spawner;
use embassy_time::Timer;

use rohi_hal::Sensor;
use rohi_hal::board::Altruist;

}

Here we import Embassy Framework related types and SDK types like Altruist and Sensor.

Main task

#[esp_hal_embassy::main]
async fn main(spawner: Spawner) {
    esp_println::logger::init_logger_from_env();

    let altruist = Altruist::init().await.unwrap();

    spawner.spawn(print_pm25_task(altruist)).ok();
}

The main task spawns first and handles basic initialization and child task launching. See the Embassy Docs for details.

Here, the Altruist hardware is initialized and stored in a local variable, then passed to the child working task print_pm25_task.

Work task

#![allow(unused)]
fn main() {
#[embassy_executor::task]
async fn print_pm25_task(mut board: Altruist) {
    let mut sensor = Sensor(&mut board);

    loop {
        info!("PM25: {:?}", sensor.pm25().await);
        Timer::after_secs(10).await;
    }
}

}

The work task handles all operations—in this case, it simply gets PM2.5 measurements and prints them to the logs (terminal).

You'll notice multiple await calls. This instruction puts the CPU to sleep until a waiting event occurs—whether it's a time interval for Timer or reading measurements from a peripheral device for sensor. Rather than running in an infinite loop checking conditions, the CPU enters a low-power mode to conserve energy and resources. During await periods, other tasks can use the CPU time to execute their operations.

Flashing

Flashing firmware is quite simple—just launch it using cargo as you would run any Rust binary.

cargo run --release --bin example-altruist-sensor-pm25

Behind the scenes, several processes occur:

  1. The Rust compiler creates a RISC-V binary;
  2. espflash detects the ESP board and flashes the firmware;
  3. espflash connects to the serial interface and displays logs.