Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Mano robótica controlada por EMG de precisión: Integración InMoov y guía de construcción

Componentes y suministros

Dispositivo uECG 3
Mano InMoov 1
Arduino Nano R3 1
Controlador PWM 16 canales PCA9685 (Adafruit) 1
Módulo nRF24 (genérico) 1

Sobre el proyecto

Nuestro equipo tiene una larga historia con manos robóticas. Durante un tiempo intentamos hacer una mano protésica fiable, pero para este proyecto uso un buen ejemplo de mano open source existente: InMoov.

No entraré en detalles del montaje de la mano – está bien descrito en la web del proyecto y es bastante complicado. Me centraré en el control, ¡que es completamente nuevo! :)
También puedes ver cómo evolucionó esta tecnología en el siguiente proyecto: Ver músculos en acción - EMG 8 canales con LEDs

1. Procesamiento de señal

El control se basa en EMG – actividad eléctrica muscular. La señal EMG se obtiene mediante tres dispositivos uECG (sé que se supone que es un monitor ECG, pero al basarse en un ADC genérico, puede medir cualquier biosignal – incluyendo EMG). Para procesamiento EMG, uECG tiene un modo especial en el que envía datos de espectro de 32 bins, y el promedio de "ventana muscular" (intensidad espectral promedio entre 75 y 440 Hz). Las imágenes de espectro se ven así:

Mano robótica controlada por EMG de precisión: Integración InMoov y guía de construcción

Aquí la frecuencia está en el eje vertical (en cada una de las 3 gráficas, frecuencia baja abajo, alta arriba – de 0 a 488 Hz con pasos ~15 Hz), el tiempo en el horizontal (datos antiguos a la izquierda, total ~10 segundos en pantalla). La intensidad se codifica en color: azul – bajo, verde – medio, amarillo – alto, rojo – más alto. Para reconocimiento fiable de gestos, se requiere un procesamiento PC adecuado de estas imágenes. Pero para activación simple de dedos de mano robótica, basta con usar el valor promedio en 3 canales – uECG lo proporciona cómodamente en ciertos bytes de paquete para que el sketch Arduino lo analice. Estos valores son mucho más simples:

Mano robótica controlada por EMG de precisión: Integración InMoov y guía de construcción

Las gráficas roja, verde, azul son valores brutos de dispositivos uECG en diferentes grupos musculares cuando aprieto pulgar, anular y dedo medio respectivamente. Para nuestro ojo estos casos son claramente diferentes, pero necesitamos convertir esos valores en "puntuación de dedo" para que el programa pueda enviar valores a servos de la mano. El problema es que las señales de grupos musculares están "mezcladas": en caso 1 y 3 la intensidad de señal azul es similar – pero roja y verde son diferentes. En casos 2 y 3 las señales verdes son iguales – pero azul y roja son diferentes. Para "desmezclarlas", usé una fórmula relativamente simple:

S0 = V0² / ((V1 × a0 + b0) × (V2 × c0 + d0))

donde S0 – puntuación para canal 0, V0, V1, V2 – valores brutos para canales 0, 1, 2, y a, b, c, d – coeficientes que ajusté manualmente (a y c entre 0.3 y 2.0, b y d 15 y 20; tendrás que cambiarlos para ajustar a tu colocación de sensores). La misma puntuación se calculó para canales 1 y 2. Tras esto, las gráficas se separaron casi perfectamente:

Mano robótica controlada por EMG de precisión: Integración InMoov y guía de construcción

Para los mismos gestos (esta vez dedo anular, medio, y luego pulgar) las señales son claras y pueden traducirse fácilmente en movimientos de servos comparando con umbral.

2. Esquemáticos

Mano robótica controlada por EMG de precisión: Integración InMoov y guía de construcción

El esquemático es bastante simple: solo necesitas módulo nRF24, controlador PWM I2C PCA9685 (o similar), y fuente de alimentación 5V de alta corriente suficiente para mover todos los servos a la vez (requiere al menos 5A para operación estable).

Lista de conexiones:
nRF24 pin 1 (GND) – GND Arduino
nRF24 pin 2 (Vcc) – 3.3V Arduino
nRF24 pin 3 (Chip Enable) – D9 Arduino
nRF24 pin 4 (SPI:CS) – D8 Arduino
nRF24 pin 5 (SPI:SCK) – D13 Arduino
nRF24 pin 6 (SPI:MOSI) – D11 Arduino
nRF24 pin 7 (SPI:MISO) – D12 Arduino
PCA9685 SDA – A4 Arduino
PCA9685 SCL – A5 Arduino
PCA9685 Vcc – 5V Arduino
PCA9685 GND – GND Arduino
PCA9685 V+ – 5V alta corriente
PCA9685 GND – GND alta corriente
Servos dedos: a canales PCA 0-4, en mi notación pulgar – canal 0, índice – canal 1, etc.

3. Colocación sensores EMG

Para obtener lecturas razonables, es importante colocar los dispositivos uECG, que registran actividad muscular, en los lugares correctos. Aunque muchas opciones son posibles, cada una requiere diferente enfoque de procesamiento – comparto lo que usé:

Mano robótica controlada por EMG de precisión: Integración InMoov y guía de construcción

Puede ser contra-intuitivo, pero la señal del músculo del pulgar se ve mejor en el lado opuesto del brazo, así que uno de los sensores se coloca allí, y todos cerca del codo (los músculos tienen la mayor parte de su cuerpo en esa zona, pero conviene comprobar dónde están exactamente los tuyos – hay gran diferencia individual).

4. Código

Antes de ejecutar el programa principal, necesitas averiguar los IDs de unidad de tus dispositivos uECG (se hace descomentando línea 101 y encendiendo dispositivos uno a uno) y rellenarlos en el array unit_ids (línea 37).

#include 
#include 
#include 
#include 
#include 
#include 

#define SERVOMIN 150 // 'mínimo' longitud pulso (de 4096)
#define SERVOMAX 600 // 'máximo' longitud pulso (de 4096)

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
int rf_cen = 9; // nRF24 chip enable pin
int rf_cs = 8;  // nRF24 CS pin
RF24 rf(rf_cen, rf_cs);

// dirección pipe – hardcoded en uECG
uint8_t pipe_rx[8] = {0x0E, 0xE6, 0x0D, 0xA7, 0, 0, 0, 0};

uint8_t swapbits(uint8_t a){ // uECG usa orden de bits invertido para dirección pipe
  uint8_t v = 0;
  if(a & 0x80) v |= 0x01;
  if(a & 0x40) v |= 0x02;
  if(a & 0x20) v |= 0x04;
  if(a & 0x10) v |= 0x08;
  if(a & 0x08) v |= 0x10;
  if(a & 0x04) v |= 0x20;
  if(a & 0x02) v |= 0x40;
  if(a & 0x01) v |= 0x80;
  return v;
}

long last_servo_upd = 0; // tiempo última actualización servos
byte in_pack[32]; // array para paquete RF entrante
unsigned long unit_ids[3] = {4294963881, 4294943100, 28358}; // IDs uECG conocidos – rellenar con tus IDs
int unit_vals[3] = {0, 0, 0}; // valores uECG con esos IDs
float tgt_angles[5]; // ángulos objetivo para 5 dedos
float cur_angles[5]; // ángulos actuales para 5 dedos
float angle_open = 30; // ángulo correspondiente a dedo abierto
float angle_closed = 150; // ángulo correspondiente a dedo cerrado

void setup() {
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
  for(int x = 0; x < 8; x++)
    pipe_rx[x] = swapbits(pipe_rx[x]);
  
  rf.begin();
  rf.setDataRate(RF24_1MBPS);
  rf.setAddressWidth(4);
  rf.setChannel(22);
  rf.setRetries(0, 0);
  rf.setAutoAck(0);
  rf.disableDynamicPayloads();
  rf.setPayloadSize(32);
  rf.openReadingPipe(0, pipe_rx);
  rf.setCRCLength(RF24_CRC_DISABLED);
  rf.disableCRC();
  rf.startListening(); // escuchar datos uECG
  
  // Nota: uECG debe cambiarse a modo datos raw (pulsación larga botón)
  // para enviar paquetes compatibles; por defecto envía en modo BLE
  // que no puede recibir nRF24
  
  Serial.begin(115200); // salida serie – muy útil para depuración
  pwm.begin(); // iniciar driver PWM
  pwm.setPWMFreq(60); // Servos analógicos ~60 Hz
  
  for(int i = 0; i < 5; i++) {
    tgt_angles[i] = angle_open;
    cur_angles[i] = angle_open;
  }
}

void setAngle(int n, float angle){
  pwm.setPWM(n, 0, SERVOMIN + angle * 0.005556 * (SERVOMAX - SERVOMIN));
}

float angle_speed = 15; // velocidad movimiento dedos
float v0 = 0, v1 = 0, v2 = 0; // valores actividad muscular filtrados por 3 canales

void loop() {
  if(rf.available()){
    rf.read(in_pack, 32); // procesar paquete
    byte u1 = in_pack[3]; // ID unidad 32-bit, único por uECG
    byte u2 = in_pack[4];
    byte u3 = in_pack[5];
    byte u4 = in_pack[6];
    unsigned long id = (u1<<24) | (u2<<16) | (u3<<8) | u4;
    // Serial.println(id); // descomentar para listar tus IDs uECG
    if(in_pack[7] != 32) id = 0; // tipo paquete incorrecto: en modo EMG este byte debe ser 32
    int val = in_pack[10]; // valor actividad muscular
    if(val != in_pack[11]) id = 0; // valor duplicado en 2 bytes por ruido RF, sin CRC en nRF24
    
    // encontrar ID correspondiente y guardar valor
    for(int n = 0; n < 3; n++)
      if(id == unit_ids[n])
        unit_vals[n] = val;
  }
  
  long ms = millis();
  if(ms - last_servo_upd > 20) { // no actualizar servos demasiado a menudo
    last_servo_upd = ms;
    for(int n = 0; n < 5; n++) {
      if(cur_angles[n] < tgt_angles[n] - angle_speed/2) cur_angles[n] += angle_speed;
      if(cur_angles[n] > tgt_angles[n] + angle_speed/2) cur_angles[n] -= angle_speed;
    }
    for(int n = 0; n < 5; n++)
      setAngle(n, cur_angles[n]);
    
    // promedio exponencial: evita picos únicos afecten estado dedo
    v0 = v0*0.7 + 0.3*(float)unit_vals[0];
    v1 = v1*0.7 + 0.3*(float)unit_vals[1];
    v2 = v2*0.7 + 0.3*(float)unit_vals[2];
    
    // calculando puntuaciones desde valores brutos
    float scor0 = 4.0*v0*v0/((v1*0.3 + 20)*(v2*1.3 + 15));
    float scor1 = 4.0*v1*v1/((v0*2.0 + 20)*(v2*2.0 + 20));
    float scor2 = 4.0*v2*v2/((v0*1.2 + 20)*(v1*0.5 + 15));
    
    // imprimir puntuaciones para depuración
    Serial.print(scor0); Serial.print(' ');
    Serial.print(scor1); Serial.print(' ');
    Serial.println(scor2);
    
    // comparar cada puntuación con umbral y cambiar estados dedos
    if(scor2 < 0.5) tgt_angles[0] = angle_open;      // señal débil – abrir dedo
    if(scor2 > 1.0) tgt_angles[0] = angle_closed;    // señal fuerte – cerrar dedo
    if(scor1 < 0.5) { tgt_angles[1] = angle_open; tgt_angles[2] = angle_open; }
    if(scor1 > 1.0) { tgt_angles[1] = angle_closed; tgt_angles[2] = angle_closed; }
    if(scor0 < 0.5) { tgt_angles[3] = angle_open; tgt_angles[4] = angle_open; }
    if(scor0 > 1.0) { tgt_angles[3] = angle_closed; tgt_angles[4] = angle_closed; }
  }
}

5. Resultados

Con unos experimentos de unas 2 horas, logré una operación bastante fiable (el vídeo muestra un caso típico):

No se comporta perfectamente y con este procesamiento solo reconoce dedos abiertos y cerrados (ni siquiera cada uno de los 5, detecta solo 3 grupos musculares: pulgar, índice y medio juntos, anular y meñique juntos). Pero la "IA" que analiza la señal ocupa 3 líneas de código aquí y usa un solo valor por canal. Creo que se podría hacer mucho más analizando imágenes espectrales de 32 bins en PC o smartphone. Además, esta versión usa solo 3 dispositivos uECG (canales EMG). Con más canales debería ser posible reconocer patrones realmente complejos – pero bueno, ese es el punto del proyecto, proporcionar un punto de partida para cualquiera interesado :) El control de mano no es la única aplicación para este sistema.

Código

Esquemáticos

nrf24_hand_control_5jcEeCP8a3.fzz

Proceso de manufactura

  1. Pastillas Anticonceptivas: Historia, Beneficios, Riesgos y Producción
  2. Sistema de control de temperatura basado en LM35 con microcontrolador AT89S52
  3. Control Automático de Tren DIY con Arduino: Simple, Fiable y Personalizable
  4. Mando universal Android con Arduino, 1Sheeld y control IR
  5. Control Remoto IoT de Brazo Robótico Personalizado con Arduino MKR1000 y ThingSpeak
  6. Controla un Rover Arduino con Firmata y Mando Xbox One - Guía Completa
  7. Estudiantes construyen sistema robótico avanzado de clasificación de basura con tecnología B&R
  8. Chips fotónicos guiados por IA moldean luz de banda ancha para óptica inteligente
  9. Optimice la automatización robótica con el software de simulación avanzado 3DG
  10. Trinamic y Maxim Integrated lanzan diseño referencia para acelerar desarrollo end-of-arm tooling en robótica industrial
  11. Construye un Vehículo Robótico Inalámbrico Controlado por Sensor IR