Cómo escribir una biblioteca ArduPy
En esta guía, aprenderás a escribir una biblioteca para ArduPy desde cero, con un ejemplo que ilustra todo el flujo de trabajo. Al final, entenderás cómo desarrollar tu propia biblioteca ArduPy e implementarla en tus proyectos. Incluso puedes convertir tu biblioteca favorita de Arduino al formato de MicroPython para usarla con ArduPy.
Se requiere algo de conocimiento en programación, pero los pasos clave son sencillos de seguir.
Hardware necesario
Empezando
Te guiaremos paso a paso con un ejemplo para facilitar la comprensión.
1. Bibliotecas Arduino
Lo primero es encontrar la biblioteca ya escrita en formato Arduino. La mayoría de los módulos de Seeed la tienen y están disponibles en nuestro GitHub. Solo busca el módulo en GitHub y accede al repositorio.
En esta guía usaremos como ejemplo el sensor Grove - Temp&Humi&Barometer (BME280) y su biblioteca Arduino.
2. Estructura de una biblioteca ArduPy
Esta es la estructura típica de una biblioteca ArduPy:

Ejemplo: ArduPy para Grove-BME280
.gitignore
: lista de archivos que Git debe ignorar.travis.yml
: configuración de CI (puede ignorarse)LICENSE
: licencia del proyectoREADME.md
: documentaciónlibrary.json
: archivo principal de configuración de la biblioteca ArduPymod_ardupy_bme280.c
: código principal que conecta C con MicroPythonwrapper_ardupy_bme280.cpp
: contenedor (wrapper) de funciones
3. Escribiendo el library.json
Comienza con el archivo library.json
:
{
"name": "Seeed ArduPy BME280 ",
"version": "1.0.0",
"repository": {
"type": "git",
"url": "https://github.com/Seeed-Studio/seeed-ardupy-bme280.git"
},
"dependencies": [{
"name": "Seeed_Arduino_BME280",
"url": "https://github.com/Seeed-Studio/Grove_BME280.git"
}]
}
name
: nombre de la biblioteca ArduPy.url
dentro derepository
: enlace a tu repositorio en GitHub.dependencies
: define la biblioteca Arduino de la cual depende.
Usa el formato Seeed_Arduino_MODULO
para nombrar dependencias si es posible.
4. Escribiendo wrapper_ardupy_MODULO.cpp
Este archivo es el contenedor entre el código C++ (Arduino) y MicroPython.
Primero, incluye la biblioteca dependiente:
#include "Seeed_Arduino_BME280/Seeed_BME280.h"
Luego, incluye los encabezados compartidos:
extern "C"{
#include "py/mphal.h"
#include "py/nlr.h"
#include "py/objtype.h"
#include "py/runtime.h"
#include "shared-bindings/util.h"
}
Inicializa el módulo:
#define bme280 (*(BME280*)self->module)
void * operator new(size_t, void *);
Ahora define las funciones comunes:
extern "C" {
void common_hal_bme280_construct(abstract_module_t *self){
self->module = new (m_new_obj(BME280)) BME280();
bme280.init();
}
void common_hal_bme280_deinit(abstract_module_t *self){
bme280.~BME280();
}
float common_hal_bme280_get_temperature(abstract_module_t *self){
return bme280.getTemperature();
}
uint32_t common_hal_bme280_get_pressure(abstract_module_t *self){
return bme280.getPressure();
}
uint32_t common_hal_bme280_get_humidity(abstract_module_t *self){
return bme280.getHumidity();
}
}
construct
: crea una nueva instancia e inicializa el módulo (init()
).- Las funciones acceden directamente a los métodos Arduino (
getTemperature()
, etc).
Puedes seguir el patrón con cualquier otra función de la biblioteca Arduino.
Funciones con parámetros
Si una función de Arduino requiere parámetros, tradúcela con los tipos correspondientes.
Ejemplo:
Original en Arduino:
void setHighSolution(bool enable);
Convertido en ArduPy:
void common_hal_lis3dhtr_setHighSolution(abstract_module_t *self, bool enable) {
lis.setHighSolution(enable);
}
También puedes ver este ejemplo que toma dos parámetros.
5. Escribiendo el archivo mod_ardupy_MODULO.c
Una vez terminado el wrapper, pasamos al archivo central. Usaremos como ejemplo mod_ardupy_bme280.c
.
Primero, incluye los encabezados compartidos:
#include "py/mphal.h"
#include "py/nlr.h"
#include "py/objtype.h"
#include "py/runtime.h"
#include "py/obj.h"
#include "shared-bindings/util.h"
Declara las funciones previamente definidas en el wrapper:
void common_hal_bme280_construct(abstract_module_t *self);
void common_hal_bme280_deinit(abstract_module_t *self);
float common_hal_bme280_get_temperature(abstract_module_t *self);
uint32_t common_hal_bme280_get_pressure(abstract_module_t *self);
uint32_t common_hal_bme280_get_humidity(abstract_module_t *self);
extern const mp_obj_type_t grove_bme280_type;
Inicializa el módulo:
m_generic_make(bme280) {
abstract_module_t * self = new_abstruct_module(type);
mp_arg_check_num(n_args, n_kw, 0, 0, false);
common_hal_bme280_construct(self);
return self;
}
Reemplaza los nombres por los de tu módulo.
Define los atributos del objeto:
void bme280_obj_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest){
abstract_module_t *self = (abstract_module_t *)self_in;
uint32_t value;
float number;
if (dest[0] == MP_OBJ_NULL) {
if (attr == MP_QSTR_temperature) {
number = common_hal_bme280_get_temperature(self);
dest[0] = mp_obj_new_float(number);
return;
}
else if (attr == MP_QSTR_pressure) {
value = common_hal_bme280_get_pressure(self);
dest[0] = mp_obj_new_int(value);
return;
}
else if (attr == MP_QSTR_humidity) {
value = common_hal_bme280_get_humidity(self);
dest[0] = mp_obj_new_int(value);
return;
}
}
generic_method_lookup(self_in, attr, dest);
}
Esto expone los métodos como .temperature
, .humidity
, etc., accesibles desde MicroPython.
Define la tabla de métodos:
const mp_rom_map_elem_t bme280_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bme280_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&bme280_obj___exit___obj) },
};
MP_DEFINE_CONST_DICT(bme280_locals_dict, bme280_locals_dict_table);
Define el tipo del módulo:
const mp_obj_type_t grove_bme280_type = {
{&mp_type_type},
.name = MP_QSTR_grove_bme280,
.make_new = bme280_make_new,
.locals_dict = (mp_obj_t)&bme280_locals_dict,
.attr = bme280_obj_attr,
};
Es cuestión de reemplazar el nombre del módulo según tu implementación.
Funciones que aceptan parámetros
Si tu módulo tiene funciones que reciben parámetros, así puedes implementarlas:
Ejemplo con 1 parámetro:
mp_obj_t lis3dhtr_setHighSolution(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
{
abstract_module_t *self = (abstract_module_t *)pos_args[0];
bool enable = mp_obj_is_true(pos_args[1]);
common_hal_lis3dhtr_setHighSolution(self, enable);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(lis3dhtr_setHighSolution_obj, 1, lis3dhtr_setHighSolution);
Ejemplo con 2 parámetros:
mp_obj_t led_bar_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args){
abstract_module_t * self = (abstract_module_t *)(pos_args[0]);
uint32_t led_no = mp_obj_get_int(pos_args[1]);
float value = mp_obj_get_float(pos_args[2]);
common_hal_led_bar_set_brightness(self, led_no, value);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(led_bar_set_brightness_obj, 2, led_bar_set_brightness);
Recuerda añadir las funciones en la tabla de métodos (locals_dict
):
const mp_rom_map_elem_t lis3dhtr_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&lis3dhtr_deinit_obj)},
{ MP_ROM_QSTR(MP_QSTR_setHighSolution), MP_ROM_PTR(&lis3dhtr_setHighSolution_obj)},
{ MP_ROM_QSTR(MP_QSTR_setBrightness), MP_ROM_PTR(&led_bar_set_brightness_obj)},
// Agrega aquí más funciones si es necesario
};
6. Compilando el firmware
Una vez escrita la biblioteca ArduPy, es momento de compilarla. Puedes subir tu proyecto a GitHub, por ejemplo:
https://github.com/Seeed-Studio/seeed-ardupy-bme280
- Descarga e instala
ardupy-aip
, la herramienta para compilar bibliotecas ArduPy. Sigue esta guía.
Una vez instalada, ejecuta:
aip install [URL de tu biblioteca]
# Ejemplo:
aip install https://github.com/Seeed-Studio/seeed-ardupy-bme280
Luego compila el firmware:
aip build
Si todo va bien, deberías ver una salida como esta:

Prueba de la biblioteca
Con el firmware compilado, puedes flashearlo a tu dispositivo:
aip flash
Para acceder al modo REPL:
aip shell -c "repl"
Importa tu módulo:
from arduino import grove_bme280
Inicializa y usa tu biblioteca:
bme280 = grove_bme280()
print ("Temperatura: ", bme280.temperature, "C")
print ("Humedad: ", bme280.humidity, "%")
print ("Presión: ", bme280.pressure, "Pa")
Si llegaste hasta aquí: ¡has creado con éxito una biblioteca ArduPy!
Recursos
Existen muchas bibliotecas ArduPy disponibles para usar como ejemplo o base:
Soporte técnico y discusión
¡Gracias por usar nuestros productos! Ofrecemos varios canales de comunicación para ayudarte a tener la mejor experiencia posible. Visita nuestro foro, abre un issue en GitHub o contacta a nuestro equipo de soporte.