Create modules for ESP32 microcontrollers

If no existing modules support your hardware or software, you can create your own. To create a new module compatible with the Micro-RDK, follow these steps.

  1. Generate a new module skeleton from this template:

    cargo generate --git https://github.com/viamrobotics/micro-rdk.git
    

    Select templates/module when prompted, give the module a name of your choice, and answer any additional prompts.

    The CLI automatically initializes a git repository in the generated module directory.

  2. Navigate into the generated module directory:

    cd <path-to/your-module-directory>
    
  3. Develop the module by defining structs which implement the necessary traits and adding tests and registration hooks for them. The traits you need to implement are determined by the API you chose to implement.

    For example, to implement the sensor API, you need to implement Readings, SensorT<f64> and Status traits.

    Example implementation

    Here is an example src/lib.rs file that implements the sensor API to return random numbers:

     use std::sync::{Arc, Mutex};
     use std::collections::HashMap;
     use micro_rdk::DoCommand;
     use micro_rdk::common::config::ConfigType;
     use micro_rdk::common::registry::{ComponentRegistry, RegistryError, Dependency};
     use micro_rdk::common::sensor::{
         Sensor, SensorType, Readings, SensorError, SensorT, SensorResult,
         GenericReadingsResult, TypedReadingsResult
     };
     use micro_rdk::common::status::{Status, StatusError};
    
     pub fn register_models(registry: &mut ComponentRegistry) -> Result<(), RegistryError> {
         registry.register_sensor("my_sensor", &MySensor::from_config)
     }
    
     #[derive(DoCommand)]
     pub struct MySensor {}
    
     impl MySensor {
         pub fn from_config(_cfg: ConfigType, _deps: Vec<Dependency>) -> Result<SensorType, SensorError> {
             Ok(Arc::new(Mutex::new(MySensor {})))
         }
     }
    
     // Mark this type as a sensor
     impl Sensor for MySensor {}
    
     // Implementation for getting readings
     impl SensorT<f64> for MySensor {
         fn get_readings(&self) -> Result<TypedReadingsResult<f64>, SensorError> {
             use rand::Rng;
             let mut rng = rand::thread_rng();
             let mut readings = HashMap::new();
             readings.insert("random_value".to_string(), rng.gen());
             Ok(readings)
         }
     }
    
     // Required to convert typed readings to generic readings
     impl Readings for MySensor {
         fn get_generic_readings(&mut self) -> Result<GenericReadingsResult, SensorError> {
             Ok(self
                 .get_readings()?
                 .into_iter()
                 .map(|v| (v.0, SensorResult::<f64> { value: v.1 }.into()))
                 .collect())
         }
     }
    
     // Basic status implementation
     impl Status for MySensor {
         fn get_status(&self) -> Result<Option<micro_rdk::google::protobuf::Struct>, StatusError> {
             Ok(Some(micro_rdk::google::protobuf::Struct {
                 fields: HashMap::new(),
             }))
         }
     }
    

    For more examples, see the example module implementation walkthrough.

For further details on Micro-RDK development, including credentials management and developer productivity suggestions, please see the development technical notes page on GitHub.

Using Your Module

To use your module in a project:

  1. Follow the Build your firmware workflow in a different directory from your module. Be sure to add your module to the dependencies section of the project’s Cargo.toml file.
  2. Flash your firmware to your ESP32 microcontroller.
  3. Configure your machine to use the module.

To update your firmware with a new version of your module without a physical connection to the ESP32 microcontroller, see Over-the-air firmware updates.