El siguiente proyecto consiste en el diseño e implementación de un sistema de control para un brazo robótico, tanto en su versión física como en simulación, utilizando un microcontrolador PIC, el software LabVIEW y SolidWorks.
El sistema de control se basa en programar, en el microcontrolador PIC, la generación de señales PWM para controlar la posición del brazo robótico físico, así como la transmisión de datos de posición mediante comunicación USB. En la parte de simulación, se diseñó el brazo robótico en SolidWorks y se configuró la comunicación con LabVIEW. En LabVIEW se programó el sistema para la recepción y el acondicionamiento de los datos enviados por el microcontrolador para controlar la simulación en SolidWorks.
@microchipotle Brazo robótico con simulación en tiempo real @Justway #electronica #mecatronica #programacion #robotica #ingenieria ♬ sonido original - Microchipotle
Programación de brazo robótico solo en físico
Circuito y programación para controlar el brazo robótico solo en físico.
Se programó el microcontrolador para generar cuatro señales PWM de salida, con un período de 20 ms y un ancho de pulso de 500 µs a 2500 µs, para controlar la posición de los servomotores. La posición de los servomotores se modifica utilizando la lectura de las señales de los potenciómetros conectados a los pines analógicos del microcontrolador.
Los optoacopladores permiten aislar eléctricamente el circuito digital del circuito de potencia, evitando interferencias como caídas de voltaje y ruido eléctrico ocasionado por los servomotores. Además, proporcionan protección frente a cortocircuitos o sobrecargas que puedan generarse en la etapa de potencia.
Circuito PIC18F4550
Materiales:
- PIC18F4550
- Servomotores MG995: x3
- Servomotor MG90s
- Optoacopladores 6N137: x4
- Potenciómetros 10 K: x4
- Cristal de Cuarzo 20 MHz
- resistencias 10 K: x8
- resistencias 470: x4
- Capacitores 22 pF : x2
- Alimentación:
- Fuente 5V 1A (Servomotores)
- Fuente 5V (Circuito Digital)
Código PIC18F4550
#device ADC=10
#FUSES NOWDT //No Watch Dog Timer
#use delay(crystal=20000000,clock=48000000)
#FUSES NOMCLR
int16 tiempos[4]; // Usado para el ciclo actual
int16 tiempos_nuevos[4]; // Buffer temporal
int pines[4];
// Leer ADCs 10 bits y convierte el valor de 500us a 1950us para acho de pulso
void leer_adc() {
set_adc_channel(0); delay_us(10);
tiempos_nuevos[0] = ((int32)read_adc() * 1950 / 1023) + 500;
set_adc_channel(1); delay_us(10);
tiempos_nuevos[1] = ((int32)read_adc() * 1950 / 1023) + 500;
set_adc_channel(2); delay_us(10);
tiempos_nuevos[2] = ((int32)read_adc() * 1950 / 1023) + 500;
set_adc_channel(3); delay_us(10);
tiempos_nuevos[3] = ((int32)read_adc() * 1950 / 1023) + 500;
}
// Ordenar valores en tiempos[] y pines[]
void ordenar_servos() {
// Copiar valores desde buffer temporal
for (int i = 0; i < 4; i++) {
tiempos[i] = tiempos_nuevos[i];
pines[i] = i; // pines 0–3
}
// Ordenamiento por burbuja simple
for (int i = 0; i < 3; i++) {
for (int j = i + 1; j < 4; j++) {
if (tiempos[i] > tiempos[j]) {
int16 tmp_tiempo = tiempos[i];
tiempos[i] = tiempos[j];
tiempos[j] = tmp_tiempo;
int tmp_pin = pines[i];
pines[i] = pines[j];
pines[j] = tmp_pin;
}
}
}
}
void main() {
delay_ms(500);//Espera que la fuente se estabilice
setup_adc(ADC_CLOCK_INTERNAL);
//Habilita el timer0 16 bits
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); //5.461 ms overflow clock 48Mhz
leer_adc(); // Lectura inicial
ordenar_servos(); // Ordenamiento inicial
while (true) {
// Encender todas las salidas
output_bit(PIN_B0,1);
output_bit(PIN_B1,1);
output_bit(PIN_B2,1);
output_bit(PIN_B3,1);
int16 tiempo_espera = 0;
// Apagar cada pin después de generar el ancho de pulso
for (int i = 0; i < 4; i++) {
int16 espera = tiempos[i] - tiempo_espera;
delay_us(espera);
if (pines[i] == 0) output_bit(PIN_B0,0);
else if (pines[i] == 1) output_bit(PIN_B1,0);
else if (pines[i] == 2) output_bit(PIN_B2,0);
else if (pines[i] == 3) output_bit(PIN_B3,0);
tiempo_espera = tiempos[i];
}
//Resetea el timer y ejecución de las sub-rutinas
set_timer0(0); // Reset timer;
int16 tiempoM = tiempos[3];
leer_adc(); // Leer ADCs
ordenar_servos(); // Copiar y ordenar datos nuevos al final del ciclo
//Calcula el tiempo pasado del timer0 en microsegundos
int16 tiempo_pasado = ((int32)get_timer0()*5461)/65535; // 5461 overflow / 65535 16bits = 1/5;
// Calcula el tiempo de esperar para completar los 20 ms del periodo
int16 espera = 20000 - tiempoM - tiempo_pasado;
if (espera > 0) delay_us((int16)espera);
}
}
Descargar archivos de programación e impresión 3d
Descarga los archivos de impresión 3D y los códigos de programación para el brazo robótico, ya sea solo en su versión física o con comunicación USB incluida. También incluye la programación en LabVIEW 2020.
Servicios especializados en impresión 3D
Ahora puedes enviar tus archivos de diseño para impresión 3D o mecanizado CNC a través de plataformas como JUSTWAY y recibir una cotización instantánea de tus prototipos.
JUSTWAY también ofrece diversos servicios de impresión 3D, como estereolitografía (SLA), sinterización selectiva por láser (SLS), fusión por chorro múltiple (MJF), modelado por deposición fundida (FDM), fusión selectiva por láser (SLM) y procesamiento digital de luz (DLP). Además, cuentan con una amplia variedad de materiales de impresión, incluyendo resina, nailon, PLA, ABS, PETG, TPU, aluminio, acero inoxidable, titanio, entre otros.
¡Aprovecha su oferta especial de verano y recibe un 15 % de cashback en todos tus pedidos del 1 de junio al 31 de agosto!
Los servicios de mecanizado CNC que JUSTWAY ofrece incluyen procesos avanzados de fresado CNC de 3 ejes y fresado indexado de 5 ejes. Además, cuentan con servicios de torneado CNC, mecanizado por descarga eléctrica y una amplia gama de acabados superficiales, como pintura, pulido, cepillado, grabado láser, entre otros. También trabajan con más de 30 tipos de metales y plásticos, incluyendo aluminio, acero inoxidable, latón, cobre, titanio, fibra de carbono, baquelita, acrílico, entre otros.
Todo lo que necesitas hacer es subir tus archivos de diseño 3D o de mecanizado CNC a través de su plataforma en línea para obtener una cotización instantánea. Este servicio es ideal si quieres llevar tus proyectos al siguiente nivel, ya que ofrecen una gama de opciones de materiales de calidad y procesos de fabricación eficientes y profesionales.
Programación de brazo robótico con simulación
Circuito y programación para controlar el brazo robótico, tanto en su versión física como en simulación.
El valor de la posición de los servomotores también se utiliza para enviarlo a LabVIEW mediante comunicación USB.
En LabVIEW, se programó la comunicación con SolidWorks para controlar la simulación del brazo robótico utilizando los datos de posición recibidos desde el microcontrolador.
En SolidWorks se diseñó el brazo robótico y se realizó un estudio de movimiento utilizando el complemento SolidWorks Motion. Se generaron los motores de movimiento para los cuatro grados de libertad del brazo robótico y se configuraron con un rango de 0 a 180 grados.
Circuito PIC18F4550 con comunicación USB
Materiales:
- PIC18F4550
- Servomotores MG995: x3
- Servomotor MG90s
- Optoacopladores 6N137: x4
- Potenciómetros 10 K: x4
- Cristal de Cuarzo 20 MHz
- resistencias 10 K: x8
- resistencias 470: x4
- resistencia 1.5 K
- Capacitores 22 pF : x2
- Capacitor 22o nF
- Modulo Micro USB
- Alimentación: Fuente 5V 1A
Programación en LabVIEW 2020
El archivo de programación de LabVIEW está disponible para su descarga en la sección «Descargar archivos», ubicada en la parte superior.
Para controlar los motores de movimiento en SolidWorks desde LabVIEW, es necesario contar con el complemento «SoftMotion Module».
Configuración de motores en SolidWorks
En SolidWorks se utilizó el complemento «SolidWorks Motion» para habilitar el análisis de movimiento y la generación de los motores que definen el movimiento del brazo robótico.
Se colocó un motor en cada grado de libertad (es decir, donde se ubica el servomotor) del brazo robótico, y se configuró como un motor de tipo «distancia», con un rango de movimiento de 0 a 180 grados. Antes de crear el estudio de movimiento, cada grado de libertad del brazo debe estar en un ángulo de 0 grados, utilizando relaciones de posición. Posteriormente, se crea el estudio de movimiento y se suprimen dichas relaciones dentro del mismo.
Puedes crear un croquis circular en la pieza donde se monta el servomotor, o bien directamente en su eje, para definir la «ubicación del motor». Luego, define la «dirección» de movimiento (flecha roja). Finalmente, selecciona la pieza paralela al croquis para establecer el parámetro «Mover componente con respecto a» (pieza azul).
Código PIC18F4550 + Simulación
#device ADC=10
#FUSES NOWDT //No Watch Dog Timer
#use delay(crystal=20000000,clock=48000000,USB_FULL)
#FUSES NOMCLR
#define USB_CONFIG_BUS_POWER 500 //500ma corriente de entrada
#include "usb_cdc.h"
//Registro de trasnmision y recepcion
int16 tiempos[4]; // Usado para el ciclo actual
int16 tiempos_nuevos[4]; // Buffer temporal
int pines[4];
// Leer ADCs 10 bits y convierte el valor de 500us a 1950us para acho de pulso
void leer_adc() {
set_adc_channel(0); delay_us(10);
tiempos_nuevos[0] = ((int32)read_adc() * 1950 / 1023) + 500;
set_adc_channel(1); delay_us(10);
tiempos_nuevos[1] = ((int32)read_adc() * 1950 / 1023) + 500;
set_adc_channel(2); delay_us(10);
tiempos_nuevos[2] = ((int32)read_adc() * 1950 / 1023) + 500;
set_adc_channel(3); delay_us(10);
tiempos_nuevos[3] = ((int32)read_adc() * 1950 / 1023) + 500;
if(usb_enumerated()) //esta asignado a un puerto COM?
{
printf(usb_cdc_putc,"%04lu,%04lu,%04lu,%04lu\r\n",tiempos_nuevos[0],tiempos_nuevos[1],tiempos_nuevos[2],tiempos_nuevos[3]);
}
}
// Ordenar valores en tiempos[] y pines[]
void ordenar_servos() {
// Copiar valores desde buffer temporal
for (int i = 0; i < 4; i++) {
tiempos[i] = tiempos_nuevos[i];
pines[i] = i; // pines 0–3
}
// Ordenamiento por burbuja simple
for (int i = 0; i < 3; i++) {
for (int j = i + 1; j < 4; j++) {
if (tiempos[i] > tiempos[j]) {
int16 tmp_tiempo = tiempos[i];
tiempos[i] = tiempos[j];
tiempos[j] = tmp_tiempo;
int tmp_pin = pines[i];
pines[i] = pines[j];
pines[j] = tmp_pin;
}
}
}
}
void main() {
delay_ms(500);//Espera que la fuente se estabilice
setup_adc(ADC_CLOCK_INTERNAL);
//Habilita el timer0 16 bits
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); //5.461 ms overflow clock 48Mhz
leer_adc(); // Lectura inicial
ordenar_servos(); // Ordenamiento inicial
usb_init();
while (true) {
// Encender todas las salidas
output_bit(PIN_B0,1);
output_bit(PIN_B1,1);
output_bit(PIN_B2,1);
output_bit(PIN_B3,1);
int16 tiempo_espera = 0;
// Apagar cada pin después de generar el ancho de pulso
for (int i = 0; i < 4; i++) {
int16 espera = tiempos[i] - tiempo_espera;
delay_us(espera);
if (pines[i] == 0) output_bit(PIN_B0,0);
else if (pines[i] == 1) output_bit(PIN_B1,0);
else if (pines[i] == 2) output_bit(PIN_B2,0);
else if (pines[i] == 3) output_bit(PIN_B3,0);
tiempo_espera = tiempos[i];
}
//Resetea el timer y ejecución de las sub-rutinas
set_timer0(0); // Reset timer;
int16 tiempoM = tiempos[3];
leer_adc(); // Leer ADCs
ordenar_servos(); // Copiar y ordenar datos nuevos al final del ciclo
//Calcula el tiempo pasado del timer0 en microsegundos
int16 tiempo_pasado = ((int32)get_timer0()*5461)/65535; // 5461 overflow / 65535 16bits = 1/5;
// Calcula el tiempo de esperar para completar los 20 ms del periodo
int16 espera = 20000 - tiempoM - tiempo_pasado;
if (espera > 0) delay_us((int16)espera);
}
}
