Proyecto Exoesqueleto inferior; Piernas Roboticas para discapacitados

Hola a todos los que puedan aportar algo.

Como expliqué antes. Estoy haciendo unas piernas robóticas para una persona que a causa de un accidente perdió la habilidad de caminar y mover sus brazos. poco a poco ha recuperado movilidad parcial pero sin fuerza, tiene posibilidad de mover el brazo izquierdo.

El exoesqueleto va ya en su segunda versión y cuenta con 4 motores dos para piernas llamados m1 en pierna derecha y M3 en pierna izquierda y también dos motores para rodillas llamados M2 para rodilla derecha y m4 para rodilla izquierda. actualmente utilizo un acelerometro mma7361 por cada motor para indicar la posición del elemento que le corresponde movilizar. Y dado que estoy utilizando únicamente un ARDUINO UNO, estoy utilizando solo la señal análoga “x” para que con este valor y el valor en cuentas de 1G con la función “arcoseno” calcular el angulo de cada miembro del exoesqueleto.

Realicé un vídeo caminando (vídeo adjunto) y su posterior análisis de la dinámica de posiciones angulares de cada pierna y grafiqué la posición angular de los dos miembros de una pierna cada 100 mili-segundos (Gráfica adjunta) con esto generé la base de datos a ingresar en el código.

La base de datos está formada por cuatro variables tipo “array” con las que ingreso para cada 100 milisegundos:
a) refpos_m1 : posición esperada de m1 (femur derecho) respecto a la vertical.
b) travel_m1 : delta entre posición anterior (refpos_m1[i-1] y posición esperada (refpos_m1*)*
c) refpos_m2 : Posición esperada de m2 (pantorrilla) respecto a la vertical.
d) travel_m2 : delta entre posición anterior (refpos_m2[i-1] y posición esperada (refpos_m2*)
_
```_
float refpos_m1[31] = {25.0, 23.7, 22.3, 21.0, 19.6, 18.3, 16.9, 15.6, 14.2, 12.9, 11.5, 10.2, 8.8, 7.4, 6.1, 4.7, 3.4, 2.0, 0.7, -0.7, -2.0, 0.0, 4.0, 8.0, 12.0, 16.0, 20.0, 23.0, 24.0, 25.0, 25.0};
float travel_m1[31] = {0.0, -1.3, -1.4, -1.3, -1.4, -1.3, -1.4, -1.3, -1.4, -1.3, -1.4, -1.3, -1.4, -1.4, -1.3, -1.4, -1.3, -1.4, -1.3, -1.4, -1.3, 2.0, 4.0, 4.0, 4.0, 4.0, 4.0, 3.0, 1.0, 1.0, 0.0};

float refpos_m2[31] = {10.0, 8.7, 7.3, 5.2, 3.2, 1.1, -1.0, -3.1, -5.1, -7.2, -9.3, -11.4, -13.4, -15.5, -17.6, -19.6, -21.7, -23.8, -25.9, -27.9, -30.0, -30.0, -38.0, -46.0, -50.0, -46.0, -31.0, -15.0, -1.0, 7.0, 10.0};
float travel_m2[31] = {0.0, -1.3, -1.4, -2.1, -2.0, -2.1, -2.1, -2.1, -2.0, -2.1, -2.1, -2.1, -2.0, -2.1, -2.1, -2.0, -2.1, -2.1, -2.1, -2.0, -2.1, 0.0, -8.0, -8.0, -4.0, 4.0, 15.0, 16.0, 14.0, 8.0, 3.0};
_
```*_
El software utiliza estos cuatro datos y los de los acelerómetros para que con un angulo real calculado entre la posición donde estoy y el punto a donde va medido en grados lo multiplico por un factor unitario previamente calculado y con eso se indica la velocidad para los próximos 100 mili-segundos…
Mi codigo se ve mas o menos entendible … utilizo motores de elevador de vidrio automotrices y con una reducción por engranes muevo un elemento que simula ser el femur ó la pantorrilla para cada motor…
Anexo un video de motores y prueba del mecanismo con un código de pruebas iniciales que basé en el uso de delay´s.
Toda ayuda es bienvenida para mejorarlo.
les dejo el código que ya compila sin error para esta primer etapa del proyecto.
Deseo de corazón que todo el que lea el post esté sano… Pero imaginen que sería sin podernos mover…
Saludos
Oscar A.
El código actualizado está más delante en este mismo hilo.

debes aprender Oscar a entender los errores tal como te los muestra el compilador.
El primero no se explicarlo asi que vamos al segundo.

Codigo_de_pierna_junio3:34: error: expected ',' or ';' before 'int'

NOTA: los errores también se presentan con tag de código.
El compilador dice que en tu sketch Codigo_de_pierna_junio3 en la linea 34 se espera una ‘,’ o un ‘;’ antes del int
Para entender esto debes ir a tu IDE y agregar numeración de líneas para identificarlas mas fácilmente.
la linea 34 dice

34: int factor_m1 = 20
35: int factor_m2 = 20

asi que ves que al final falta un ‘;’ y esta antes del int
O sea que todo concuerda.
Asi puedes ir interpretando todos los errores.
Estos errores

Codigo_de_pierna_junio3:111: error: 'vel_m1' was not declared in this scope
Codigo_de_pierna_junio3:111: error: 'travel_m1' cannot be used as a function
Codigo_de_pierna_junio3:115: error: 'travel_m1' cannot be used as a function

Dicen que las variables vel_m1, no ha sido declarada dentro del loop
esto se debió a que vel_m1 tampoco tiene el ‘;’ al final en una linea como la 36
travel_m1 y travel_m1 no pueden usarse como funciones
Dice esto porque tu usaste

vel_m1 = factor_m1 * travel_m1(i) * (1+ correccion_m1);

en lugar de usar

vel_m1 = factor_m1 * travel_m1<[i] * (1+ correccion_m1);

un simple cambio de () por
con esos errores puede ser que los demás no aparezcan.

Enterado, por la mañana que tenga el ordenador haré los cambios. Solo tengo una duda. Agregaste un símbolo “<” entre la variable travel_m1 y el (i) … Si busco el valor que se encuentra en la posición “i” del array, ese símbolo "< " lo debo usar siempre?

No. Eso fue un error de tipeo mío
Lo correcto es

vel_m1 = factor_m1 * travel_m1[i] * (1+ correccion_m1);

Esto es un hermoso proyecto!
Como tal lo muevo al foro correspondiente!
Mis felicitaciones para Oscar!

Oscar ya hemos hablado por privado pero para POTENCIAR este proyecto te invito en la medida de tus tiempos que vayas sumando información que complemente lo que haces, porque el código luce descolocado con muchas otras cosas que necesitaría un lector para reproducir este proyecto.
Es un tema complejo, con muchos servos y sensores.
Ademas hacerlo atraerá mas gente que aporte y contribuya cada uno con lo que pueda.

Hola, es cierto faltan varias partes del proyecto y precisamente la etapa en que me encuentro es en la que hay varias tareas pendientes, recién terminé de montar en una tarjeta preperforada los dos acelerometros mma7361 que utilizare para identificar la posición angular de muslo y pantorrilla. (hace un minuto terminé de soldar aquí en la oficina... me falta montarlos en casa que será mañana.. me falta idear la manera en que el usuario le dirá al controlardor si quiere sentarse ó pararse y cuantos pasos va a dar o como pararlo al llegar a su destino caminando... tengo mucho por hacer.. seguramente requeriré el filtro para evitar rebotes en un pulsador etc... Yo no paro.. siempre le estoy avanzando...

Saludos
Oscar

Hoy 8 de junio hice la primera prueba del software en la pierna derecha. Presentó demasiada inestabilidad... Creo que darle capacidad de mover variables lo complicó demasiado.. Requiero fijar el valor F del factor multiplicador y re calcularlo para que sea estable en pruebas iniciales y una vez afinado activar la corrección dinámica.

Mañana haré eso y subiré alguna foto o video.

Saludos

Imposible seguirte.
Perdona porque esto que diré solo te plantea trabajo y no respuestas pero para ayudarte tienes que darle un contexto mas claro. No se entiende que haces, cómo o por qué?
No has planteado el proyecto de manera ingenieril.
No hay esquemas, dibujos.. fotos que digan motor 1, motr 5, sensor 1 sensor N
Necesitamos entender para poder ayudarte en algo y criticarlo!!

Entenderás que solo es un crítica constructiva.

Modifiqué la descripción inicial del proyecto pero no me dejó cambiar el código por exceder lineas de mensaje … espero que ahora si suban los vídeos y el código nuevo.

#include <math.h>
 
 //correccion para factor
 float correccion_m1;
 float correccion_m2;
  
 float refpos_m1[31] = {25.0, 23.7, 22.3, 21.0, 19.6, 18.3, 16.9, 15.6, 14.2, 12.9, 11.5, 10.2, 8.8, 7.4, 6.1, 4.7, 3.4, 2.0, 0.7, -0.7, -2.0, 0.0, 4.0, 8.0, 12.0, 16.0, 20.0, 23.0, 24.0, 25.0, 25.0};
 float travel_m1[31] = {0.0, -1.3, -1.4, -1.3, -1.4, -1.3, -1.4, -1.3, -1.4, -1.3, -1.4, -1.3, -1.4, -1.4, -1.3, -1.4, -1.3, -1.4, -1.3, -1.4, -1.3, 2.0, 4.0, 4.0, 4.0, 4.0, 4.0, 3.0, 1.0, 1.0, 0.0};

 float refpos_m2[31] = {10.0, 8.7, 7.3, 5.2, 3.2, 1.1, -1.0, -3.1, -5.1, -7.2, -9.3, -11.4, -13.4, -15.5, -17.6, -19.6, -21.7, -23.8, -25.9, -27.9, -30.0, -30.0, -38.0, -46.0, -50.0, -46.0, -31.0, -15.0, -1.0, 7.0, 10.0};
 float travel_m2[31] = {0.0, -1.3, -1.4, -2.1, -2.0, -2.1, -2.1, -2.1, -2.0, -2.1, -2.1, -2.1, -2.0, -2.1, -2.1, -2.0, -2.1, -2.1, -2.1, -2.0, -2.1, 0.0, -8.0, -8.0, -4.0, 4.0, 15.0, 16.0, 14.0, 8.0, 3.0};
 
 // lectura directa de acelerometros
 float m1xval       = 0;  
 float m2xval       = 0;
   
 //angulo directo del acelerometro ya con centrado
 float degreePos_m1 = 0;
 float degreePos_m2 = 0;
   
 //relación de aceleracion en x / radio 
 double rel_m1_xr   = 0;
 double rel_m2_xr   = 0;
 
 //viaje angular real realizado en paso anterior   
 float traveled_m1  = 0;
 float traveled_m2  = 0;
 
 float refpos_m1_en_i_menos2 = 0;
 float refpos_m2_en_i_menos2 = 0;
 float deltalocalm2pasoanterior = 0;
 float error_m2;
 float travelm1=0;
 float travelm2=0;
 
 //viaje angular calculado para paso siguiente   
 float avance_m1  = 0;
 float avance_m2  = 0;
 
 
 // factor multiplicador por cada grado de giro en 0.1 seg para velocidad
 int factor_m1 = 25;
 int factor_m2 = 12;
 
 // velocidad de motores en siguiente paso PWM
 int vel_m1 = 0;
 int vel_m2 = 0;
 
 
  void setup() {
    
  // Motor_1 control pin initiate;
    pinMode(4, OUTPUT);     
    pinMode(5, OUTPUT);    
    pinMode(9, OUTPUT);
   
   // Motor_2 control pin initiate;
    pinMode(7, OUTPUT);     
    pinMode(8, OUTPUT);    
    pinMode(10, OUTPUT);
   
    analogReference(EXTERNAL);
    Serial.begin(57600);

    //Enable the Motor Shield output;  
    pinMode(6, OUTPUT); 
    digitalWrite(6, HIGH);  
  }
  
  
  void loop() {
  
  //Que quieres que haga? levantarme, sentarme, caminar, detenerme
  
  //si es caminar
  //1° Confirmar Posición vertical
  //listo para caminar?
  //1° Boton o señal de entrada SI
  //2° Dar medio paso inicial
  //3° iniciar caminata
  //loop para paso de 3 seg de mi peli 2 
  
  
  for (int pasos=1; pasos <= 10; pasos++){
    
    factor_m1 = 25; //teorico 28
    factor_m2 = 12; //teorico 13
    
  for (int i=1; i <= 30; i++){

   // factor_m1 = 10; //teorico 28
    //factor_m2 = 5; //teorico 13
    
      //entradas de acelerometro
      m1xval = analogRead(0);
      m2xval = analogRead(1);

      m1xval = map(m1xval, 0, 1023, 500, -500);
      m2xval = map(m2xval, 0, 1023, 500, -500);

      //ajustes de centrado por offset
      m1xval = m1xval - 10;  //ajuste de cero G
      m2xval = m2xval - 10;  //ajuste de cero G
     
      //calculo de relacion entre lectura corregida /maximo a 1G
      rel_m1_xr =((double)m1xval / 238);
      rel_m2_xr =((double)m2xval / 238);
     
      //calculo de angulos reales
      degreePos_m1=asin(rel_m1_xr);            //Calculo de angulo M1 en radianes
      degreePos_m1=degreePos_m1*(57.2958);    //Calculo de angulo M1 en grados
      degreePos_m2=asin(rel_m2_xr);            //Calculo de angulo M2 en radianes
      degreePos_m2=degreePos_m2*(57.2958);      //Calculo de angulo M2 en grados
     
      //Calculos para corrector de factor de velocidad
      traveled_m1 = degreePos_m1 - ((refpos_m1[i-1]) - (travel_m1[i-1])); //cambio angular realizado en paso anterior m1
      correccion_m1 = (1+ abs (travel_m1[i-1]))/(1+abs (traveled_m1)); // inverso de cumplimiento ya implicito
      correccion_m1 = constrain(correccion_m1, 0.8, 1.25);
      avance_m1 = (refpos_m1[i] - degreePos_m1);
      
      travelm1 =travel_m1[i-1];
      error_m2 = refpos_m2[i-1] - degreePos_m2 ; 
      travelm2 = travel_m2[i-1];
      traveled_m2 = travel_m2[i-1] - error_m2 - traveled_m1;
      correccion_m2 = (1+ abs (travelm2 + travelm1))/ (1+ abs ( traveled_m2));
      correccion_m2 = constrain(correccion_m2, 0.8, 1.25);
      avance_m2 = (refpos_m2[i] - degreePos_m2) - (avance_m1);
      
     //Motor 1 (muslo derecho)
     //speed in motor_1 is 
     factor_m1 = factor_m1 * correccion_m1;
     factor_m1 = constrain (factor_m1,20, 25 );
     vel_m1 = abs (factor_m1 * avance_m1);
     vel_m1 = constrain(vel_m1, 1, 180);// puse 1 en vez de cero
     analogWrite(9, vel_m1);    // set the motor_1 speed ;
     
     //dirección de rotación: positiva = 1,0 negativa =0,1
     if ( avance_m1 > 0 )
     {
     digitalWrite (4, HIGH);
     digitalWrite (5, LOW);
     }
     else
     { 
     digitalWrite (4, LOW);
     digitalWrite (5, HIGH);
     }
     
     //Motor 2 (pantorrilla derecha)
     //speed in motor_2 is 
     factor_m2 = factor_m2 * correccion_m2;
     factor_m2 = constrain (factor_m2, 8, 12 );
     vel_m2 = abs(factor_m2 * avance_m2) ;
     vel_m2 = constrain(vel_m2, 1, 125); //puse 1 en vez de cero
     analogWrite(10, vel_m2);    // set the motor_2 speed ;
     
     //dirección de rotación: positiva = 1,0 negativa =0,1
     if (avance_m2 > 0)   
     {
     digitalWrite(7, HIGH);
     digitalWrite (8, LOW);
     }
     else
     {
     digitalWrite(7, LOW);
     digitalWrite (8, HIGH);
     }
      Serial.write("valor de i =");
      Serial.print(i);
      Serial.write("\n");
      
      //datos de m1
      Serial.write("Angulo_en_M1= ");
      Serial.print(degreePos_m1);
      
      Serial.write(" traveled_m1= ");
      Serial.print(traveled_m1);
  
      Serial.write(" correccion_m1= ");
      Serial.print(correccion_m1);
      
      Serial.write(" factor_m1= ");
      Serial.print(factor_m1);
      
      Serial.write(" vel_m1= ");
      Serial.print(vel_m1);
      Serial.write("\n");
      
      
      //datos de m2
      Serial.write("Angulo_en_M2= ");
      Serial.print(degreePos_m2);
      
      Serial.write(" traveled_m2= ");
      Serial.print(traveled_m2);
  
      Serial.write(" correccion_m2= ");
      Serial.print(correccion_m1);
      
      Serial.write(" factor_m2= ");
      Serial.print(factor_m2);
      
      Serial.write(" vel_m2= ");
      Serial.print(vel_m2);
      Serial.write("\n");  
      
      delay (77);
    }
  }
  
  Serial.write("10 pasos");
  delay (3000);
  }

en un momento subiré los vídeos y gráficas ya que no pude en primer intento.

1 Like

Si tu código supera 9000 caracteres entonces adjúntalo. Es la única justificación para adjuntar un código. Sino debe mostrarse con tag de código como bien has hecho.

espero que el post de inicio ya editado y con gráficos ahora si te de una mejor idea de lo que busco...

como podrás ver hay un "Factor" multiplicador que al calcular el viaje para la siguiente decima de segundo se multiplican entre si y nos arroja la velocidad necesaria para arribar al punto deseado.

Además de eso antes se compara el cambio angular logrado en paso anterior con el logrado y de esa relación se incrementa o decrementa el "factor" para cada decima de segundo.

Trate de contener el rango de incremento y decremento del factor.. pero aun asi tengo demasiada inestabilidad y golpeteos. espero me puedas criticar el codigo.

saludos

Hola Oscar!

Para analizar un proyecto debe ser esto, un proyecto, no unas líneas de código aisladas y sin contexto.

Yo creo que habría que comenzar por el principio, es decir… cómo exactamente interacciona el exoesqueleto con el usuario. Es decir, cómo sabe el sistema lo que quiere el usuario. Y después, como reacciona a los elementos exteriores, por ejemplo, un obstaculo que impide al motor avanzar. Y finalmente, como le devuelve la información al usuario.

Tu proyecto tambien puede ser: Posicionamiento multiarticular con dos articulaciones en 2D (me ha parecido entender que no quieres giro). Es mas mecánico, claro, y menos “comercial”, pero al menos se puede definir mejor qué debe hacer el sistema.

Como eres Ingeniero Civil lo entenderás perfectamente, a mi me falta la “memoria del proyecto”.

Eso aparte el trabajo que haces me parece admirable.

Un abrazo y animo

Hola como ya todos saben, soy novato en programacion en arduino, pero puedo darte un punto de vista, el exoesqueleto que queres hacer es para rehabilitacion o es para hacer caminar a una persona que no camina, si es para rehabilitacion no has tratado de usar sensor muscle v3 en vez de acelerometros y usar motores nema 17, yo estoy empezando un proyecto igual y voy a usar estos componentes, si te interesa comunicate por privado y vemos si nos podemos ayudar mutuamente, saludos desde Mendoza, Argentina