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

Construye un Actuador Lineal Servo de Precisión con Retroalimentación de Posición – Guía Paso a Paso

En este tutorial aprenderemos a fabricar un actuador lineal servo. A diferencia de los actuadores lineales convencionales que se mueven en una dirección al aplicar tensión, este actuador lineal servo personalizado ofrece movimientos precisos y repetibles que se controlan fácilmente.

Se llama actuador servo porque incorpora un sistema de lazo cerrado (feedback) mediante el cual controlamos con precisión el movimiento de salida.

Puedes ver el siguiente vídeo o leer el tutorial escrito a continuación.

Resumen

La entrada para controlar este actuador lineal servo puede ser analógica o digital. En caso de entrada analógica, puede ser cualquier potenciómetro: lineal, rotativo común, o un joystick (que es otro potenciómetro rotativo), etc.

En caso de entrada digital, controlamos el actuador con un transmisor RC. Para esta configuración también necesitamos un receptor RC que vaya como entrada al actuador.

En ambos modos (analógico y digital) solo necesitamos 3 hilos para conectar: 2 para alimentar el dispositivo de entrada y el 3.º para la señal.

Una función genial es que podemos definir una posición inicial y final personalizadas para la varilla de salida, así como ajustar la sensibilidad o rapidez de respuesta del actuador a nuestra entrada.

Pero mi función favorita es la capacidad de controlar este actuador desde un PC o portátil mediante comunicación serie. Introducimos valores en milímetros en el Monitor Serie del Arduino IDE y el actuador se mueve a esa posición.

Aún mejor: podemos hacer movimientos repetibles, o guardar posiciones, tecleando «save» en el monitor serie en cada posición deseada, y luego ordenar al actuador que repita los movimientos en bucle tecleando «run».

Ahora te explico todo lo que necesitas saber sobre este actuador lineal servo personalizado, cómo funciona y cómo lo diseñé, para que tú también puedas construir uno.

Cómo Funciona

El sistema de control de lazo cerrado se basa en el sensor de posición rotativa magnético AS5600 y el control PID implementado para pilotar el motor DC.

De hecho, uso la misma placa controladora de servo personalizada que hice en mi vídeo anterior, que incluye su propio microcontrolador y todo lo necesario para convertir fácilmente cualquier motor DC en un servo motor independiente.

Puedes ver ese tutorial para una explicación detallada de cómo funciona un servo motor y un sistema de lazo cerrado.

Resumiendo: un servo motor es un sistema de lazo cerrado donde la señal de entrada (posición deseada) se compara con la posición real del motor que obtenemos del sensor de retroalimentación.

La diferencia (error) se procesa en el controlador, que manda al motor moverse hasta alcanzar la posición deseada.

Este actuador lineal servo tiene el mismo principio que un servo motor, pero con un paso adicional: convertir el movimiento rotativo del motor en movimiento lineal mediante un mecanismo de husillo.

Diseño del Actuador Lineal Servo

Aquí tienes el modelo 3D del actuador, donde vemos cómo funciona todo.

El sensor AS5600 está en la parte trasera y rastrea la rotación del husillo. El husillo que uso tiene paso de 8 mm, así que cada vuelta completa la tuerca avanza 8 mm lineales.

El AS5600 es un encoder de 12 bits: 4096 posiciones por vuelta. Dividiendo 8 entre 4096 obtenemos una resolución de 0,001953 mm. Ese es el cambio de posición más pequeño que detecta. Bastante impresionante.

El motor DC que uso es de 12 V con reductor integrado que da 480 RPM. 480 / 60 = 8 rev/s; multiplicado por 8 mm de paso da 64 mm/s de velocidad lineal.

Me parece ideal: el recorrido máximo de la varilla es 150 mm, así que tarda ~2,5 s de extremo a extremo a velocidad máxima, o ~3 s con aceleración y frenado. Por eso usé relación 1:1 para accionar el husillo.

El diseño del actuador se basa en el tamaño del PCB del controlador servo personalizado y del husillo y tuerca. El PCB mide 40 × 40 mm, así que ese era el tamaño mínimo del bloque cilíndrico.

La tuerca de husillo de 8 mm tiene 22 mm de diámetro exterior, y según eso diseñé la varilla. Tuerca y varilla se unen con cuatro tornillos M3 e insertos roscados. En la parte superior de la varilla hay un rodamiento que desliza sobre el bloque cilíndrico, guiando la varilla e impidiendo su rotación.

En el tapón del cilindro de salida hay 4 rodamientos pequeños que guían la varilla al salir.

En conjunto, el actuador resulta bastante compacto considerando todos los componentes.

También logré integrar un microinterruptor de fin de carrera dentro del bloque cilíndrico, usado para homing y definir la posición inicial.

Descarga del Modelo 3D

Puedes ver y explorar el modelo 3D de este actuador lineal servo personalizado directamente en tu navegador con Onshape (necesitas cuenta Onshape, puedes crear una gratis para uso doméstico).

Puedes obtener los archivos STL para impresión 3D, así como el archivo STEP del modelo 3D, en Cults3D.

Una cosa más: puedes aumentar fácilmente la carrera máxima alargando el bloque cilíndrico y la varilla. Elegí estas dimensiones para que todas las piezas entren en impresora con cama de 220 × 220 mm. La pieza más grande es la varilla, de 215 mm.

Impresión 3D

Mi nueva Creality Ender-3 V3 SE hizo un gran trabajo imprimiendo en orientación horizontal sobre el eje Y. Aunque hace falta un poco de lijado, imprimir la varilla así aporta funcionamiento más suave y varilla más resistente.

Al imprimir en 3D es importante usar la Expansión Horizontal en tu laminador para compensar la expansión del filamento y obtener piezas dimensionalmente precisas.

Usé –0,1 mm, pero haz pruebas para ver qué valor va mejor en tu impresora.

Imprimí el bloque cilíndrico en vertical (eje Z) para evitar muchos soportes. La Ender-3 V3 SE también lo hizo genial.

Me sorprendió gratamente la calidad de impresión de esta impresora por su precio. Es súper fácil de montar, tiene nivelación automática, extrusor directo, gran calidad y velocidades de hasta 250 mm/s. Todo por menos de 200 $ la convierte en una de las mejores para presupuestos ajustados.

Consulta esta impresora en la tienda Creality o Amazon. También mi análisis detallado en mi web.

Montaje

Bien, aquí están todas las piezas impresas para empezar a montar el actuador lineal.

Lista de Piezas

Puedes conseguir los componentes para este proyecto de Actuador Lineal Servo en los enlaces:

Mecánicos:

Electrónicos:

Nota: Son enlaces de afiliado. Como asociado de Amazon gano por compras que califiquen.

Montaje del Mecanismo de Husillo

Primero instalamos el husillo en el bloque base del cilindro. Para ello, insertamos esta tuerca impresa en 3D que tiene la misma rosca que el husillo.

Cuesta un poco enroscar la tuerca en el husillo porque es ajuste forzado, pero eso es lo que queremos. Esta tuerca soporta toda la fuerza cuando la varilla empuja, así que cuanto más apretado, más fuerza aguanta. Además, la tuerca tiene orificio para inserto roscado para fijarla al eje con tornillo sin cabeza.

El husillo se sujeta en el bloque base con dos rodamientos de 22 mm exterior.

En la parte trasera va el engranaje que mueve el husillo. Este engranaje también tiene rosca compatible y dos orificios para insertos roscados para fijarlo al husillo con tornillos sin cabeza.

Esta unión es crítica porque transmite todo el par del motor al husillo, así que no debe resbalar.

Para hacer este subconjunto, primero ponemos los insertos roscados en el engranaje y la tuerca, y algunos en el bloque cilíndrico.

Enroscamos el engranaje y la tuerca en sentido contrario pero sin pasarnos, pues añade fuerzas axiales a los rodamientos. Luego, con tornillos sin cabeza, fijamos la tuerca y el engranaje al husillo.

Una vez fijados, vemos que el husillo aún no está bloqueado. Hay que añadir esta placa al bloque cilíndrico para que los rodamientos se queden en su sitio.

Esto completa el subconjunto: el husillo queda firme pero gira libremente.

Preparamos la varilla. Es hueca en toda su longitud para albergar el husillo. Para unir la tuerca del husillo y la varilla, primero ponemos insertos roscados.

En la parte superior de la varilla instalamos el rodamiento guía de 13 mm exterior y 6 mm interior.

Colocamos el rodamiento sobre un eje hueco de 6 mm impreso en 3D y lo fijamos a la varilla con tornillo avellanado M3 de 10 mm. La varilla ya está lista y vemos cómo desliza por las guías del cilindro.

Unimos el cilindro al bloque base. Antes, instalamos el microinterruptor de fin de carrera.

Primero soldamos cables en la conexión NC. Cables de ~15 cm. Pasan por un orificio en la parte superior del cilindro y fijamos el microinterruptor al cilindro con dos tornillos M2 de 8 mm.

Necesitas específicamente este modelo de microinterruptor para que el rodamiento guía lo accione en el momento justo sin golpear nada. Si no lo encuentras, puedes modificar orificios y mecanismo.

Para unir el cilindro al bloque base ponemos insertos roscados y fijamos con dos tornillos M4 de 25 mm. Solo ponemos los dos superiores por ahora; los inferiores irán luego al instalar la tapa de la caja de engranajes y PCB, pues usan los mismos orificios.

Enroscamos la varilla en el husillo. El rodamiento guía debe quedar entre los carriles guía del cilindro.

Girando el engranaje trasero, la varilla retrocede hasta topar con el microinterruptor.

Luego ponemos el tapón del cilindro. Este aloja cuatro rodamientos pequeños de 9 mm exterior. Los ejes para estos rodamientos pueden ser impresos en 3D.

Cuidado al insertarlos, la zona es muy fina y se rompe fácil. A mí se me rompió varias veces; asegúrate de que entren holgados. Estos rodamientos apoyan y guían la varilla para funcionamiento suave.

El tapón se fija con cuatro tornillos M4.

Instalación del Motor DC

Insertamos el motor DC. Lo fijamos con seis tornillos M3. Luego ponemos el engranaje en el eje del motor.

Para fijar el engranaje usamos dos insertos roscados y tornillos sin cabeza.

Una vez engranados correctamente, pasamos a colocar la tapa de engranajes y PCB en la parte trasera. Para ello, ponemos más insertos roscados en el bloque base.

Conectamos cables al motor DC. En mi caso los soldé directamente.

Los cables deben medir ~20 cm. Hay un orificio en el bloque base por donde pasan los cables del motor y del fin de carrera.

También los pasamos por dos retenedores en la tapa, que los mantienen alejados del engranaje.

Fijamos la tapa al bloque base. Primero ponemos los dos tornillos M4 inferiores, pero no del todo: dejamos 2–3 mm para meter el soporte de la tapa entre medio y luego aprietamos todo junto.

Esta operación es un poco liada, pero tuvo que ser así porque quería la tapa lo más compacta posible e impresa en una pieza, y los soportes del PCB bloqueaban el paso de los tornillos.

Instalación del PCB Controlador Servo Personalizado

Una vez lista la tapa, instalamos la placa controladora servo personalizada. Como dije, es el mismo controlador del vídeo anterior donde mostré cómo convertir cualquier motor DC en servo.

El componente principal es el encoder AS5600, que rastrea la posición angular del imán en el eje de salida. Aquí pegaremos el imán al engranaje de salida del husillo. El imán queda perfectamente alineado con el AS5600 al meter la PCB.

Para fijar la PCB, primero insertamos tuercas M2 en las ranuras de los soportes y luego apretamos la PCB con cuatro tornillos M2.

Queda conectar cables. Los del motor van al bornier del motor, comprobando la polaridad para que coincida con el programa del controlador.

Antes de conectar el motor a la PCB, podemos aplicarle tensión para verificar que el mecanismo de husillo funciona.

Los cables del fin de carrera: como no tengo pines dedicados, soldé el de masa al pad de masa del condensador electrolítico, y el NC al pin SCK (pin digital 13 del ATmega328).

El bornier de alimentación está junto al lateral de la tapa, así que pasé un conector de alimentación 5,5 mm por el orificio.

Puse disipador al driver DC. Finalmente, ponemos la tapa a presión en la parte trasera y ¡listo, proyecto terminado!

Ahora podemos conectar cualquier potenciómetro o receptor RC a los pines de entrada correspondientes y controlar la posición del actuador.

Como mencioné, en el vídeo anterior expliqué en detalle cómo funciona este controlador, su esquema y cómo hice el PCB.

Deberías ver ese tutorial si quieres fabricar esta placa controladora.

Esquema de Circuito

Resumiendo: el componente principal es el sensor AS5600, que rastrea la posición de la salida del actuador. Los datos del sensor van al cerebro, el microcontrolador Atmega328, que hace los cálculos y manda al driver DRV8871 cómo pilotar el motor DC.

El DRV8871 aguanta hasta 3,6 A pico. Alimentamos la placa con 12 V, que el AMS1117 baja a 5 V para el Atmega328 y demás componentes de 5 V. Un DIP switch de dos canales selecciona el modo de entrada: analógico, digital o comunicación serie.

Uno de los potenciómetros multivuelta ajusta la sensibilidad, y el pulsador SDM sirve para definir posiciones inicial y final.

Pedí el PCB a PCBWay. Subes el Gerber, eliges propiedades y lo pides a buen precio.

Diseñé el PCB a 4 capas, las intermedias para GND, lo que sube un poco el precio. No cambié propiedades por defecto salvo color blanco, y acepté cambio de acabado superficial a oro por inmersión si aplica sin cargo extra.

Puedes encontrar y descargar el Gerber en la comunidad de proyectos compartidos de PCBWay, desde donde también puedes pedirlo directamente.

De todos modos, también puedes hacer este actuador lineal sin este controlador personalizado, claro.

Puedes usar el AS5600 en placa breakout junto con una Arduino para pilotar el motor DC.

Código

Veamos el código de este Actuador Lineal Servo:

/* Actuador Lineal Servo - Código Arduino por Dejan, www.HowToMechatronics.com
Librerías:
Encoder AS5600: https://github.com/RobTillaart/AS5600
Controlador PID: https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.h */
#include "AS5600.h"
#include "Wire.h"
#include 
AS5600 as5600; // usar Wire por defecto
double Pk1 = 0.65; // velocidad de llegada
double Ik1 = 0;
double Dk1 = 0.1;
// Variables para PID
double Setpoint, Input, Output;
PID myPID(&Input, &Output, &Setpoint, Pk1, Ik1, Dk1, DIRECT);
#define motor_IN1 5
#define motor_IN2 6
#define ch1 2
#define setButton 7
#define inputSwitch 3
#define modeSwitch 4
#define limitSwitch 13
int ch1Value;
long encoderValue, desiredValue, pwmValue;
String serialInput = "";
int serialIntInput;
double totalDistance = 0;
long startPosition = 358;
long endPosition = 6750;
long rangeAdjustment = 0;
float sensitivityAdjustment = 0;
float angle = 0;
float angleValue = 0;
float rodPosition;
float positionsArray[100];
int positionsCounter = 0;
long quadrantNumber = 2;
long previousQuadrantNumber = 3;
long numberOfTurns = 0;
float totalAngle = 0;
char incomingByte = 0;
int intInput = 0;

void setup() {
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("AS5600_LIB_VERSION: ");
  Serial.println(AS5600_LIB_VERSION);
  Wire.begin();
  pinMode(motor_IN1, OUTPUT);
  pinMode(motor_IN2, OUTPUT);
  // Pull-ups internos
  pinMode(setButton, INPUT_PULLUP);
  pinMode(inputSwitch, INPUT_PULLUP);
  pinMode(modeSwitch, INPUT_PULLUP);
  pinMode(limitSwitch, INPUT_PULLUP);
  // Configuración PID
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(-255, 255);
  myPID.SetSampleTime(20);
  // --- HOMING ----
  // Retroceder hasta...
  while (digitalRead(limitSwitch) != 1) {
    digitalWrite(motor_IN1, LOW);
    analogWrite(motor_IN2, 70);
    encoderValue = as5600.readAngle();
  }
  while (digitalRead(limitSwitch) != 0) {
    analogWrite(motor_IN1, 50);
    digitalWrite(motor_IN2, LOW);
  }
  digitalWrite(motor_IN1, LOW);
  digitalWrite(motor_IN2, LOW);
  startPosition = as5600.readAngle() * 0.087890625;
  endPosition = 6000;
  Setpoint = startPosition;
  // --- FIN HOMING ---
}

void loop() {
  // Leer encoder - posición actual
  rodPosition = as5600.readAngle() / 0.001953125; // en mm - Husillo 8 mm/vuelta, encoder RAW 4096/vuelta, 8/4096 para mm
  // Modo comunicación serie - Leer datos del monitor serie
  if (digitalRead(modeSwitch) == 0) {
    while (Serial.available() > 0) {
      serialInput = Serial.readString();
      serialInput.trim();
      // Si se envía "save", guardar posición actual
      if (serialInput == "save") {
        positionsArray[positionsCounter] = totalDistance;
        delay(1000);
        positionsCounter++;
      }
      // Limpiar posiciones guardadas
      if (serialInput == "clear") {
        memset(positionsArray, 0, sizeof(positionsArray));
        positionsCounter = 0;
      }
      // Convertir String a Entero y usarlo como Setpoint
      serialIntInput = serialInput.toInt();
      if (serialIntInput != 0) {
        if (serialIntInput < 0) { serialIntInput = 0; }
        if (serialIntInput > 150) { serialIntInput = 150; }
        Setpoint = serialIntInput * 45; // convertir mm a grados (1 mm = 45° rotación)
      }
    }
    // Ejecutar posiciones guardadas
    if (serialInput == "run") {
      while (serialInput != "stop") {
        for (int i = 0; i <= positionsCounter - 1; i++) {
          if (serialInput == "stop") { break; }
          while (positionsArray[i] > totalDistance + 25 || positionsArray[i] < totalDistance - 25 || pwmValue != 0) {
            Setpoint = positionsArray[i];
            readEncoder();
            runMotor();
          }
          delay(2000); // pausa entre pasos
          // Comprobar comando stop en monitor serie
          while (Serial.available() > 0) {
            serialInput = Serial.readString();
            serialInput.trim();
          }
        }
      }
    }
  }
  // Modo potenciómetro y receptor RC
  else if (digitalRead(modeSwitch) == 1) {
    if (digitalRead(inputSwitch) == 0) {
      // Entrada analógica - Potenciómetro
      desiredValue = analogRead(A0);
      if (desiredValue < 15) { desiredValue = 15; }
      if (desiredValue > 1008) { desiredValue = 1008; }
      Setpoint = map(desiredValue, 15, 1008, startPosition, endPosition);
    } else if (digitalRead(inputSwitch) == 1) {
      // Entrada digital - Transmisor RC
      desiredValue = pulseIn(ch1, HIGH, 30000); // Leer receptor RC
      if (desiredValue < 1000 || desiredValue > 2000) { desiredValue = 1000; }
      Setpoint = map(desiredValue, 1000, 2000, startPosition, endPosition);
    }
  }
  // Limitar setpoint
  if (Setpoint > endPosition) { Setpoint = endPosition; }
  if (Setpoint < startPosition) { Setpoint = startPosition; }
  // Ajuste sensibilidad (comentado)
  // Pk1 = analogRead(A2) * 0.002;
  // myPID.SetTunings(Pk1, Ik1, Dk1);
  // Leer encoder y ejecutar PID
  readEncoder();
  runMotor();
  // Definir inicio y fin pulsando botón "set"
  if (digitalRead(setButton) == LOW) {
    delay(3000);
    if (digitalRead(setButton) == LOW) {
      endPosition = totalDistance;
      while (digitalRead(setButton) != HIGH) ;
    } else {
      startPosition = totalDistance;
    }
  }
}

void readEncoder() {
  // Convertir valores RAW a ángulo para rastrear posición angular del eje
  encoderValue = as5600.readAngle() * 0.087890625;
  // Cuadrante 1
  if (encoderValue >= 0 && encoderValue <= 90) { quadrantNumber = 1; }
  // Cuadrante 2
  if (encoderValue >= 90 && encoderValue <= 180) { quadrantNumber = 2; }
  // Cuadrante 3
  if (encoderValue >= 180 && encoderValue <= 270) { quadrantNumber = 3; }
  // Cuadrante 4
  if (encoderValue >= 270 && encoderValue <= 360) { quadrantNumber = 4; }
  if (quadrantNumber != previousQuadrantNumber) {
    // Transición 4º a 1º
    if (quadrantNumber == 1 && previousQuadrantNumber == 4) { numberOfTurns++; }
    // Transición 1º a 4º
    if (quadrantNumber == 4 && previousQuadrantNumber == 1) { numberOfTurns--; }
    previousQuadrantNumber = quadrantNumber;
  }
  if (totalDistance >= 0) {
    totalDistance = (numberOfTurns * 360) + encoderValue;
  } else {
    totalDistance = (numberOfTurns * 360) + encoderValue;
  }
  // Valor Input para PID
  Input = totalDistance;
}

void runMotor() {
  // Proceso PID para obtener Output
  myPID.Compute();
  // Mover derecha
  if (Output > 1) {
    pwmValue = Output;
    if (pwmValue < 50 && pwmValue > 15) { pwmValue = pwmValue + 40; }
    if (pwmValue <= 15) { pwmValue = 0; }
    analogWrite(motor_IN1, pwmValue);
    digitalWrite(motor_IN2, LOW);
  }
  // Mover izquierda
  else if (Output < 1) {
    pwmValue = abs(Output);
    if (pwmValue < 50 && pwmValue > 15) { pwmValue = pwmValue + 40; }
    if (pwmValue <= 15) { pwmValue = 0; }
    digitalWrite(motor_IN1, LOW);
    analogWrite(motor_IN2, pwmValue);
  }
  // Quieto
  else if (Output > -1 && Output < 1) {
    pwmValue = 0;
    digitalWrite(motor_IN1, LOW);
    digitalWrite(motor_IN2, LOW);
  }
}

Descripción del Código

Empezamos el bucle leyendo el encoder (posición actual) y convirtiéndolo a milímetros.

// Leer encoder - posición actual
rodPosition = as5600.readAngle() / 0.001953125; // en mm - Husillo 8 mm/vuelta, encoder RAW 4096/vuelta, 8/4096 para mm

Si estamos en «Modo comunicación serie», leemos lo que introducimos en el Monitor Serie. Si la entrada es «save» guardamos la posición actual, si es «clear» borramos todas las guardadas.

// Modo comunicación serie - Leer datos del monitor serie
if (digitalRead(modeSwitch) == 0) {
  while (Serial.available() > 0) {
    serialInput = Serial.readString();
    serialInput.trim();
    if (serialInput == "save") {
      positionsArray[positionsCounter] = totalDistance;
      delay(1000);
      positionsCounter++;
    }
    if (serialInput == "clear") {
      memset(positionsArray, 0, sizeof(positionsArray));
      positionsCounter = 0;
    }

Si la entrada es un número (0–150), lo usamos como setpoint.

// Convertir String a Entero y usarlo como Setpoint
serialIntInput = serialInput.toInt();
if (serialIntInput != 0) {
  if (serialIntInput < 0) { serialIntInput = 0; }
  if (serialIntInput > 150) { serialIntInput = 150; }
  Setpoint = serialIntInput * 45; // convertir mm a grados (1 mm = 45°)
}

Introducimos valores en mm, pero para rastrear el eje rotativo usamos grados, así que convertimos multiplicando por 45 (1 mm lineal = 45° rotación). Si tu husillo tiene otro paso, este número cambia.

Si tecleamos «run», con bucles while y for el programa recorre las posiciones guardadas repetidamente.

// Ejecutar posiciones guardadas
if (serialInput == "run") {
  while (serialInput != "stop") {
    for (int i = 0; i <= positionsCounter - 1; i++) {
      if (serialInput == "stop") { break; }
      while (positionsArray[i] > totalDistance + 25 || positionsArray[i] < totalDistance - 25 || pwmValue != 0) {
        Setpoint = positionsArray[i];
        readEncoder();
        runMotor();
      }
      delay(2000);
      while (Serial.available() > 0) {
        serialInput = Serial.readString();
        serialInput.trim();
      }
    }
  }
}

En modo potenciómetro y receptor RC, comprobamos si la entrada es analógica o digital.

// Modo potenciómetro y receptor RC
else if (digitalRead(modeSwitch) == 1) {
  if (digitalRead(inputSwitch) == 0) {
    // Analógico - Potenciómetro
    desiredValue = analogRead(A0);
    if (desiredValue < 15) { desiredValue = 15; }
    if (desiredValue > 1008) { desiredValue = 1008; }
    Setpoint = map(desiredValue, 15, 1008, startPosition, endPosition);
  } else if (digitalRead(inputSwitch) == 1) {
    // Digital - Transmisor RC
    desiredValue = pulseIn(ch1, HIGH, 30000);
    if (desiredValue < 1000 || desiredValue > 2000) { desiredValue = 1000; }
    Setpoint = map(desiredValue, 1000, 2000, startPosition, endPosition);
  }
}

Si analógico, leemos el potenciómetro y usamos su valor como setpoint. Si digital, leemos el receptor RC y usamos ese valor como setpoint.

Luego llamamos a readEncoder() y runMotor() para leer la posición actual y ejecutar el control PID. En readEncoder() leemos el sensor en valores angulares y con los if seguimos en qué cuadrante está el eje.

void readEncoder() {
  encoderValue = as5600.readAngle() * 0.087890625;
  if (encoderValue >= 0 && encoderValue <= 90) { quadrantNumber = 1; }
  if (encoderValue >= 90 && encoderValue <= 180) { quadrantNumber = 2; }
  if (encoderValue >= 180 && encoderValue <= 270) { quadrantNumber = 3; }
  if (encoderValue >= 270 && encoderValue <= 360) { quadrantNumber = 4; }
  if (quadrantNumber != previousQuadrantNumber) {
    if (quadrantNumber == 1 && previousQuadrantNumber == 4) { numberOfTurns++; }
    if (quadrantNumber == 4 && previousQuadrantNumber == 1) { numberOfTurns--; }
    previousQuadrantNumber = quadrantNumber;
  }
  if (totalDistance >= 0) {
    totalDistance = (numberOfTurns * 360) + encoderValue;
  } else {
    totalDistance = (numberOfTurns * 360) + encoderValue;
  }
  Input = totalDistance;
}

Con esto rastreamos la rotación del eje y cuándo da vueltas completas. El ángulo total es el Input del PID.

Con la entrada analógica del potenciómetro multivuelta ajustamos la ganancia proporcional del PID, y finalmente ejecutamos el proceso PID para obtener un valor de salida.

// Ajuste sensibilidad
// Pk1 = analogRead(A2) * 0.002;
// myPID.SetTunings(Pk1, Ik1, Dk1);
void runMotor() {
  myPID.Compute();
  if (Output > 1) {
    pwmValue = Output;
    if (pwmValue < 50 && pwmValue > 15) { pwmValue = pwmValue + 40; }
    if (pwmValue <= 15) { pwmValue = 0; }
    analogWrite(motor_IN1, pwmValue);
    digitalWrite(motor_IN2, LOW);
  } else if (Output < 1) {
    pwmValue = abs(Output);
    if (pwmValue < 50 && pwmValue > 15) { pwmValue = pwmValue + 40; }
    if (pwmValue <= 15) { pwmValue = 0; }
    digitalWrite(motor_IN1, LOW);
    analogWrite(motor_IN2, pwmValue);
  } else if (Output > -1 && Output < 1) {
    pwmValue = 0;
    digitalWrite(motor_IN1, LOW);
    digitalWrite(motor_IN2, LOW);
  }
}

Usamos ese valor de salida para pilotar el motor DC con PWM, izquierda, derecha o parado, según el error entre posición deseada y real que lee el encoder.

Los tres términos del PID (proporcional, integral, derivativo) se definen al inicio, y ajustándolos conseguimos distintas respuestas.

double Pk1 = 0.65;
double Ik1 = 0;
double Dk1 = 0.1;

La calidad de respuesta del actuador depende directamente de estos valores.

Pruebas

Probando la precisión: vuelve a su sitio decentemente. Moví la varilla 1 mm cada vez. El primer movimiento fue ~0,8 mm en vez de 1 mm, pero los 4 siguientes estuvieron cerca de 1 mm. El movimiento de 4 mm tuvo ~0,15 mm de error.

La varilla tiene un juego (backlash) de ~0,25 mm entre husillo y tuerca. Además, probablemente hay juego en los engranajes impresos y en los del motor.

Si aplicamos fuerza a la varilla y probamos precisión, el error aumenta, pero se puede mejorar ajustando el PID.

Esto es todo por este tutorial. ¡Espero que lo hayas disfrutado y aprendido algo nuevo!

Proceso de manufactura

  1. Dominando el rectificado sin centros: Fundamentos y beneficios
  2. Estimación Precisa de Costes en Mecanizado CNC y Fabricación
  3. Cómo Elegir la Mejor Empresa de Diseño y Desarrollo de Producto Industrial
  4. Producción Eficiente de Acero con Hornos de Inducción Sin Núcleo de Media Frecuencia
  5. Lectura de Sensores Analógicos con Raspberry Pi y Zabbix: Guía Paso a Paso
  6. Puerta automática con Arduino y sensor ultrasónico HC-SR04
  7. Soluciones Avanzadas de Impresión Flexográfica y de Envasado para Industrias Modernas
  8. Laminación en Tren de Bandas en Caliente: Desde el Recalentamiento hasta el Bobinado
  9. Cizallas hidráulicas: Soluciones de corte de metal de precisión
  10. Cómo Elegir el Transporte de Cargas Pesadas Adecuado: Patines de Rodillos, Patines para Maquinaria y Carretillas
  11. Acero para Herramientas Explicado: Propiedades Clave y Aplicaciones en Construcción y Fabricación