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

Piloto automático para veleros (sistema de gobierno automático)

Componentes y suministros

Arduino UNO
× 1
Arduino Nano R3
× 1

Acerca de este proyecto

Prefacio:

Me encanta navegar solo porque cuando un hombre está en el mar con su velero tiene todo lo que necesita para evolucionar a un nivel superior. Navegar en mar embravecido con mal tiempo puede resultar muy duro pero si elige días de buen tiempo con sol y buen viento el disfrute será al máximo.

La felicidad significa horizontes infinitos, técnica atlética perfecta, elecciones óptimas, ¡pero también cosas humanas como una buena bebida y un sabroso sándwich! Exactamente en este momento viene en ayuda el piloto automático:funciona en su lugar mientras usted toma su té y galletas de las 5:00 pm en el mar. :-)

Qué puede hacer el piloto automático por usted:

Un velero no tiene motor y no puede seguir un camino programado desde el puerto hasta la playa, luego hasta el lugar de pesca, dar la vuelta al faro y regresar, por sí solo, no puede.

Todo el trabajo lo hace el Marinero, tenemos que entenderlo en este punto:recortar velas, controlar el tiempo y la fuente / velocidad del viento, endurecer o soltar las cuerdas, cuidar el tráfico con otras embarcaciones, decidir el rumbo y el gobierno ... Cuando el Marinero decide hacer una pausa, digamos sólo 10 segundos o unos minutos más (la famosa "hora del té"), enciende el piloto automático. En una taza de segundos su GPS adquiere la posición, velocidad y dirección de la embarcación y es capaz de mantener la dirección (ruta). El sistema de dirección, una palanca conectada al timón, generalmente movida por las manos expertas de Sailor, ahora está bajo el control del piloto automático a través del motor paso a paso conectado a él por poleas y cuerdas.

Controla el timón es un trabajo continuo de afinación fina o bruta. Más pequeño (más ligero) es el barco y mayores serán los cambios de dirección factores que influyen en él:olas del mar, dirección y presión del viento, desplazamiento del peso a bordo por movimientos marineros, corrientes marinas. Pero el Sailor siempre está despierto, incluso con el piloto automático activado, y realiza cambios en la ruta real mediante el control remoto . :tiene 4 botones, etiquetados +1 -1 +10-10, para cambios pequeños o grandes en grados, aumentando o disminuyendo el valor. Estos botones están presentes en el piloto automático también, los verdes (derecha) y los rojos (izquierda). El botón azul (medio) es para activar o desactivar el piloto automático, la pausa. También es un botón negro para configurar parámetros en la memoria.

El circuito:

El procesamiento principal lo realiza MCU Arduino Uno . El otro MCU, Arduino Nano , es el perro guardián:sé que existe una especie de perro guardián dentro del Uno pero me gustaba hacerlo con un microcontrolador externo independiente, es un sueño de toda la vida que cubrí, ¡ahora estoy feliz! Uno tiene que alimentar a Nano por medio del pin 3 -> A0 poniéndolo alto / bajo, 5/0 voltios, al menos una vez cada 2.5 segundos (feedInterval); si no, significa que el Uno está "durmiendo" o "bloqueado", y Nano reinicia el Uno ... Nunca sucedió todavía, ¿puedes creerlo?

Se utiliza una pantalla popular junto con un convertidor de circuito i2c ambos soldados juntos, finalmente usando solo 4 cables para ahorrar significativamente pines digitales para comunicarse con Uno. También la forma de conectar botones y control remoto Se realiza mediante divisores de voltaje de resistencia para alcanzar el objetivo de usar la menor cantidad posible de puertos de MCU; Elegí resistencias de precisión del 1%, los valores de comparación analógica deben estar entre los valores que puse en el código; en caso de que no se reconozcan algunos botones porque elige otro tipo de resistencias, simplemente haga algunos cambios en las constantes también (modifique el código en "checkRfRC ()" y "checkHWButtons ()"). El circuito de control remoto (RC) RF 433Mhz funciona bien; para mejorar la cobertura de distancia y las posibilidades de éxito, agregué una antena en espiral que podrías hacer tú mismo con un trozo de alambre de cobre; Lo probé a 10 metros de distancia, pero creo que puede funcionar incluso a 20 metros o más, más que suficiente considerando que el velero objetivo que usé para probar Autopilot tiene solo 4,20 metros de eslora.

Para la unidad GPS Usé al principio un buen EM406A pero desafortunadamente descubrí que sufría de Week-Rollover-Bug, era demasiado viejo, luego tuve que cambiarlo por un excelente y popular Beitian BN-220T. Con su software de configuración, configúrelo para "escupir" 2 veces por segundo (2Hz), solo la frase en serie NMEA "$ GNRMC" necesaria. El GPS envía datos en serie (TX) al pin 0 (RX) de Uno. Los datos contienen todos los datos de navegación utilizados para calcular la corrección a realizar por el motor:fecha, hora, posición, latitud y longitud, rumbo verdadero, velocidad y validez de los satélites fijados. Debido al hecho de que la programación IDE de Arduino también usa el puerto pin 0 (RX), recuerde desconectar temporalmente el GPS durante esta operación ...

Otro sueño mío era usar una EEPROM . El IC 2404 es un hermoso circuito integrado i2c de 512 bytes que solía leer / escribir en este chip de memoria. Algunos parámetros para los movimientos del motor paso a paso explicaré más adelante en el párrafo "Software".

Lista de componentes:

  • Arduino Uno como MCU
  • Arduino Nano como WatchDog
  • GPS Beitian BN-220T
  • Motor paso a paso, modelo 23LM, 54 pasos =1/4 de revolución
  • Controlador Keyes L298 para motor
  • RF433Mhz RC XD-YK04 + control remoto de 4 botones + antena de bobina
  • 6 botones normalmente abiertos (2xRed, 2xGreen, 1xBlack y 1xBlue)
  • Interruptor de encendido / apagado (blanco)
  • Conectores redondos hembra + macho de 6 pines para motor paso a paso externo
  • Timbre
  • Pantalla LCD1602 2x16 caracteres + circuito convertidor i2c
  • 3 LED (rojo, azul y amarillo))
  • IC 24c04 i2c eeprom
  • Multiplexor IC 4051
  • Batería LiPo 2s 7.4v 2600mA
  • Regulador de voltaje IC 7805 + disipador de calor
  • Termistor NTC MF52-103 10k
  • Fusible reiniciable 2A
  • 6 diodos 1N4148 (D1-D6)
  • Resistencias en el escudo de potencia (R1-R4 =10k, R5 =100k)
  • Resistencias en el blindaje del piloto automático (R1 =330, R2 =1k, R3 =2k, R4 =5.1k, R5 =1k, R6 / R7 / R14 =330, R8-R13 =10k, R15 =10M)
  • Condensadores (C1 =470uF 16v, C2 =100n)
  • Resistencia de 2 W 0,22 ohmios (R6)
  • Alfileres macho
  • Encabezados de pines largos femeninos
  • Estuche transparente e "impermeable"

Hay algunos sensores en el circuito, todo conectado a Arduino Uno con la ayuda del multiplexor IC 4051 . Es un termistor para controlar la temperatura del disipador de calefacción del regulador de voltaje, una resistencia de 2W y 4x10k como divisores de voltaje para calcular el amperio como consumo de energía de todo el circuito. También el voltaje de la batería se toma bajo control:se sabe que los LiPo son críticos cuando los elementos individuales se descargan por debajo de 3.3v; este circuito tiene un LiPo de dos elementos (2S) en un paquete, en caso de bajo voltaje (por debajo de 7.0v) el zumbador le informará con pitidos breves y rápidos. ¡No espere demasiado para apagar y recargar pronto! Los Leds :el amarillo parpadeando a 1Hz le permite saber que el WatchDog está funcionando; el azul está encendido cuando el piloto automático está encendido, apagado si está en pausa; el led rojo parpadea cuando se presiona uno de los botones del control remoto.

Todo el circuito funciona a 5.0v suministrado por batería LiPo 2S 7.4v 2600mA / hy regulador de voltaje IC 7805 . La corriente no debe ser superior a 800 mA, pero suele rondar entre 100 y 450 mA. Ponle un disipador de calor . El termistor se coloca sobre él y el zumbador sonará si la temperatura supera los 50 ° C.

Las placas de circuito impreso PCB y el ensamblaje:

Se utilizan PCB de una cara por esa razón tuve que incluir algunos puentes de cable (los de línea punteada) para resolver rutas para circuitos completos. Aquí se muestran las caras de los componentes, pero a continuación tiene todos los archivos, componentes y caras de soldadura, en espejo, para descargar e imprimir mediante una impresora láser en hojas "amarillas" o "azules". Usé los amarillos pero dicen que los azules son mejores (pero el precio es significativamente más alto). Cuando imprima, recuerde desactivar la configuración de ahorro de tóner, utilice en su lugar una resolución de 1200 ppp para obtener un resultado de negro real profundo. El proceso de transferencia de tóner de las hojas mágicas a los PCB se realiza mediante el uso de una plancha caliente ... La impresión en ambas caras, también en la cara de los componentes, facilita el reconocimiento de la posición de los elementos e incluso hace que el proyecto sea "profesional".

Ambos PCB están dimensionados para encajar uno sobre el otro Arduino Uno como una pila :Primero unidad de potencia, luego unidad de piloto automático sobre todo.

Mi elección ha sido juntar todas las cosas, PCB, MCU, RC, circuito de controlador de motor, batería, GPS, botones, interruptor, cables, conectores, etc. pensando en reutilizarlos algún día:no los soldaré juntos, yo usado encabezados y cables / conexiones populares de Dupont en lugar de. Hay alrededor de 200 conexiones sin soldar, lo que significa que pueden ocurrir fallas inesperadas y no deseadas o un comportamiento diferente del circuito de vez en cuando, es normal. La sugerencia es soldar todo para un circuito más estable!

Configuración de parámetros y valores de los sensores de visualización:

Pulsando el botón negro en el lateral de la caja entra en modo de configuración ; esto se puede hacer también durante la navegación activa, no es necesario ingresar primero en Pausa. La primera página de la pantalla muestra el voltaje de la batería (V =7.83), el consumo de energía (mA =177) y la temperatura del sensor del termistor cerca del disipador (38 ° C); presionando una y otra vez el botón negro se ingresa a las páginas siguientes; las páginas 2, 3, 4 y 5 muestran los parámetros que se enumeran a continuación y puede cambiar estos valores mediante los botones -1 y +1. La sexta página muestra "Actualizando ..." si cambió algo, los valores se guardan en la memoria EEPROM.

  • Intervalo: es decir, 2000 mseg, es el tiempo entre un intento y otro del motor paso a paso para restaurar el rumbo "H" a la ruta "R", moviendo la palanca del timón hacia la derecha o hacia la izquierda;
  • Mínimo: es decir, 2 °, es la cantidad mínima de grados fuera de ruta para tener la intervención del piloto automático; hasta este valor, el timón permanece fijo en la posición central;
  • Máx .: es decir, 40 °, es el cambio máximo de dirección a la vez por motor paso a paso; si el cálculo realizado es para un cambio de 50 °, en realidad el Stepper se moverá solo 40 °;
  • Coeficiente: es decir, 1,50 x °, es el coeficiente de cambio de dirección a la vez; si el cálculo realizado es para un cambio de 40 °, en realidad el motor paso a paso se moverá (40 x 1,50) =60 °;

Estos parámetros son necesarios para ajustar el piloto automático cuando se instala en el barco de vela. La respuesta, la sensibilidad y la suavidad dependen del diámetro de las poleas, cuántas poleas, el diámetro de la polea principal del motor paso a paso, la sensibilidad del timón, la longitud de la palanca del timón conectada, etc. Deje que instale todo y deje que intente hacer experiencia a bordo. ¡Por supuesto, elija un hermoso día soleado con viento suave para toda la fase de prueba!

Cómo funciona "en vivo":

Estás navegando por el mar, el lago o simplemente alrededor del puerto. Es la hora del té y tu coca y tu sándwich favorito te esperan en el bolsillo. Aquí estamos: cambiar piloto automático activado y deje que tome la posición del GPS satelital, ahora debe leer en la pantalla la velocidad real en nudos, el reloj y la dirección del rumbo, es decir, H270 ° (R =ruta a seguir, H =rumbo real) en grados (recuerde 180 ° =sur, 270 ° =oeste, 360 ° o 0 ° =norte y 90 ° =este). Los valores R y H son los mismos en el modo de pausa (se muestra STOP). Conecte ahora la cuerda de dirección, desde el motor paso a paso hasta la palanca del timón, y presione el botón azul para iniciar la dirección del piloto automático ; en este punto, el piloto automático mantiene R =dirección de la ruta y controla lo que sucede con H =rumbo. Seguro que el número de título cambia , lento o rápido dependiendo de las condiciones meteorológicas de las que ya hablamos. Luego, el piloto automático intenta restaurar a R =dirección de la ruta haciendo correcciones, es decir, -10 °, + 5 °, etc.hasta que el valor H sea igual al valor R . Puede decidir algunos cambios en la ruta y puede modificar el número usando los botones rojo y verde en la unidad (-1 -10 +1 +10) o por medio del control remoto. Para recuperar el control de el dirección solo tienes que presionar el botón azul Pause, desconectar la cuerda de la palanca del timón continuando el trabajo con tus manos. Bien hecho.

Lado del software:

El código es bastante largo, pero espero que sea lo suficientemente claro como para que sea fácil de entender. En cualquier caso te explicaría cómo está. El boceto utiliza alrededor del 65% del programa y alrededor del 45% de la memoria. Incluso usando la clase String, principalmente para la manipulación de oraciones en serie NMEA, todo el flujo de elaboración es estable y sólido; utiliza "serialEvent ()" para recibir datos del GPS dos veces por segundo , luego llama a "nmeaExtractData ()" y finalmente verifica el paquete de datos con "nmea0183_checksum () para asegurarse de la integridad de los datos. Si usa otra marca y modelo de GPS, asegúrese de que las oraciones tengan la misma estructura o debe hacer algunos cambios aquí . Por ejemplo, EM406A usa el ID de paquete "$ GPRMC" , BT220 usa "$ GNRMC" en su lugar ... solo un pequeño cambio de nombre ... Un enlace útil puede ayudarlo con la prueba de suma de comprobación:https://nmeachecksum.eqth.net - Aquí un ejemplo de una oración NMEA completa, contiene :id, hora, validez, latitud, longitud, velocidad, rumbo verdadero, fecha, variación y suma de comprobación.

$ GPRMC, 095836.000, A, 4551.9676, N, 01328.7118, E, 2.09, 341.84, 280519 ,, * 08

Durante "Configuración ()" se comprueba la EEPROM :si es nuevo o desconocido, está inicializado (formateado). Los parámetros en la memoria se leen / escriben como bytes:0 =0x29, 1 =0x00, 2-3 =intervalo, 4-5 =min, 6-7 =max, 8-11 =coeficiente (byte, byte, int, int, flotador). Manejé con cuidado las operaciones EEPROM r / w, quizás demasiado a la defensiva ... Los sensores se revisan cada 10 segundos a través de "readMuxSensors ()" por multiplexor y puede causar una alarma si la batería está baja o la temperatura es alta. La resolución del consumo de energía es baja, pasos de alrededor de 40 mA. Botones de hardware y RC se controlan continuamente; lo que hacen depende del valor booleano "IsSetup", así como la pantalla "RefreshDisplay ()" lo hace . El núcleo del código es la sección CONTROL DE DIRECCIÓN que llama a la función "gomotor ()" para mover el Stepper hacia afuera y hacia atrás ; sí, puede mover el timón 10 ° a la derecha y después del valor del intervalo se mueve de regreso a la posición cero del timón, y así sucesivamente después de una nueva ronda de cálculo. Como ya se dijo, el trabajo de dirección también se realiza durante la configuración porque afecta solo a algunos botones y al comportamiento de la pantalla. Alimentación de perros es muy simple pero importante:simplemente activa / desactiva su Pin tan pronto como pueda.

Cómo instalarlo en un velero:

Como se muestra en la imagen de abajo elegí colocar el piloto automático y el motor paso a paso en la popa, ambos bien fijados con pernos, etc .; una cuerda de 6 mm de diámetro parte de la polea del motor principal y recorre otras dos poleas colocadas a ambos lados. Estas dos poleas deben estar "fijadas" a la embarcación mediante dos anillos de bungee para mantener ligeramente tensada la cuerda. En este punto, finalmente, debes decidir cómo conectar la cuerda al timón (conexión temporal); tiene que estar conectado mientras desea que el piloto automático esté en acción, fácil de conectar y fácil de desconectar. ¡Mantenga el sistema de piloto automático alejado del agua! :-)

Noticias y actualizaciones:

  • 10.05.2020, agregado para descargar archivos de proyecto CAD 3D .STEP para polea paso a paso (por mí) y placa de montaje (por Andrew Barney), y una imagen de vista previa en 3D de ellos.

Descargo de responsabilidad y advertencias:

Digamos que este es un juego que estamos jugando aquí, nada a ¡tómatelo en serio! Hace unos años hice un largo viaje, 16 meses, alrededor del mundo en un velero. Navegamos extensamente con un piloto automático real (NO ESTO ¡UNO!) en todas las condiciones climáticas, incluso en malas condiciones climáticas. Un piloto automático real es algo muy fuerte tanto el hardware como el software tienes que confiar en mucho. Este piloto automático Arduino en su lugar es un juego fantástico para jugar con y para dedica tiempo a divertirte.

¡Diviértete!

Marco Zonca

Código

  • Bosquejo del piloto automático (para Uno)
  • Boceto de WatchDog (para Nano)
Boceto del piloto automático (para Uno) Arduino
 / * Este boceto actúa como piloto automático para veleros pequeños, por Marco Zonca, Arduino UNO 2019 como CPU, Arduino Nano como perro guardián, GPS BT-220 nmea, motor paso a paso + controlador, rf433Mhz RC, 6 botones, zumbador, i2c pantalla, 2 leds, i2c 24c04 eeprom, Mux 4051 para sensores, lipo 2s 7.4v 2600mA, regulador de voltaje 7805, termistor; * / # incluye  #include  #include  # include  String inputString =""; String nm_time ="00:00:00"; String nm_validity ="V"; String nm_latitude ="ddmm.mmmm'N"; String nm_longitude ="dddmm.mmmm'E "; String nm_knots =" 0.0kn "; float nmf_knots =0.0; String nm_truecourse =" 360 "; float nmf_truecourse =360; String nm_date =" dd / mm / aaaa "; String nm_routetofollow =" 000 "; float nmf_routetofollow =0; unsigned long previousStearingMillis =0; unsigned long currentStearingMillis =0; unsigned long prevCheckSensorsMillis =0; unsigned long currCheckSensorsMillis =0; int CheckSensorsInterval =10000; bool stringComplete =false; bool isfirstfix =true; bool ispause =true; bool isStearing =false; bool isSetup =false; int s =0; int y =0; int z =0; int d =0; int rfRemoteControlValue =0; int HWButtonValue =0; int SetupParameter =0; float calcmove =0; float cm =0; float Stearing =0; float prevStearing =0; float t =0; int EEdisk =0x50; int EEid1 =0x29; int EEid2 =0x00; unsigned int EEaddress =0; unsigned int EEbytes =12; byte EEdata [12]; byte EEbytedata; int EEerr =0; float SensorVBatt =0; float SensorVRes =0; float SensorTemp =0; float SensormAmp =0; // los siguientes parámetros son los predeterminados pero se leen / escriben eeprom // eeprom se inicializa si en las direcciones 0 y 1 el contenido es diferente dirección len tipo notas // 0-255 bytes en 0x50 EEdisk, 256-512 bytes en 0x51 (no usado) ---------- -------------------------------------------------- --- // 0 1B byte 01001001 (0x29 como proyecto de piloto automático id1) // 1 1B byte 00000000 (0x00 "" id2) int StearingInterval =2000; // milisegundos entre try y back 2 2B int StearingInterval 1000-5000 pasos 100int StearingMinToMove =2; // grados_de_brújula 4 2B int StearingMinToMove 0-20 pasos 1int StearingMaxMove =40; // grados_de_brújula 6 2B int StearingMaxMove 10-45 pasos 1float StearingCoeffMove =1.5; // utilizado como (grados_de_brújula * coeff) 8 4B float StearingCoeffMove 0.1-4 pasos 0.1 // 12 libres // byte bStearingInterval [sizeof (int)]; byte bStearingMinToMove [sizeof (int)]; byte bStearingMaxMove [sizeof (int)]; byte bStearingCoeffMove [sizeof (float)]; int prev_StearingInterval =0; int prev_StearingMinToMove =0; int prev_StearingMaxMove =0; float prev_StearingCoeffMove =0; const int ledpausePin =2; const Mucho int watchDogPin =3 // 00 =Vin 01 =Vbatt 10 =Tempconst int MuxSelBit1Pin =6; // const int motorsABenablePin =13; const int MuxIOPin =14; const int ButtonsPin =15; const int rfRemoteControlPin =16; const int speakerPin =17; const int RCleftbutton =201; const int RCrightbutton =202; const int RCleft10button =203; const int RCright10button =204; const int HWleftbutton =101; const int HWrightbutton =102; const int HWpausebutton =103; const int HWsetupbutton =104; const int HWleft10button =105; const int HWright10button =106; const int motorSteps // 200 para modelo 23LM, 54 pasos =1/4 de revolución LiquidCrystal_I2C lcd (0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVO); Motor paso a paso (motorStepsPerRevolution, 9, 10, 11, 12 ); void setup () {Serial.begin (4800); lcd. comienzo (16,2); Wire.begin (); motor.setSpeed ​​(60); inputString.reserve (200); pinMode (motorsABenablePin, OUTPUT); pinMode (MuxSelBit0Pin, SALIDA); pinMode (MuxSelBit1Pin, SALIDA); digitalWrite (motorsABenablePin, LOW); digitalWrite (MuxSelBit0Pin, BAJO); digitalWrite (MuxSelBit1Pin, BAJO); pinMode (ledpausePin, SALIDA); pinMode (watchDogPin, SALIDA); digitalWrite (ledpausePin, BAJO); digitalWrite (watchDogPin, BAJO); // leer + comprobar EEPROM (formatear si es nuevo (o no identificado)) lcd.clear (); lcd.setCursor (0,0); lcd.print ("Comprobación de memoria ..."); lcd.setCursor (0,1); para (s =0; s  =CheckSensorsInterval) {readMuxSensors (); if ((SensorVBatt <=7.0) || (SensorTemp>
 =50)) {lcd.clear (); lcd.setCursor (0,0); lcd.print ("¡Sensores de alarma!"); lcd.setCursor (1,1); lcd.print ("V ="); lcd.print (SensorVBatt); lcd.print (""); lcd.print (int (SensorTemp)); lcd.write (0xDF); lcd.print ("C"); NewTone (speakerPin, 10); retraso (1000); noNewTone (); } prevCheckSensorsMillis =currCheckSensorsMillis; } // CONTROL DE DIRECCIÓN ---------------- currentStearingMillis =millis (); if (currentStearingMillis - previousStearingMillis> =StearingInterval) {if (isStearing ==false &&ispause ==false) {// intenta (mueve stearing) calcmove =nmf_routetofollow - nmf_truecourse; if (calcmove <(-180)) {calcmove =calcmove + 360; } else {if (calcmove> (+180)) {calcmove =calcmove - 360; }} if (abs (calcmove)> =StearingMinToMove) {if (abs (calcmove)> =StearingMaxMove) {if (calcmove <0) {cm =(StearingMaxMove * -1); calcmove =cm; } else {cm =(StearingMaxMove * 1); calcmove =cm; }} Stearing =(calcmove * StearingCoeffMove); gomotor (int ((Stearing * 216) / 360)); // 54 pasos =1/4 de revolución prevStearing =Stearing; isStearing =true; }} else {// retroceder (mover el timón a la posición "cero") if (isStearing ==true) {Stearing =(prevStearing * -1); gomotor (int ((Stearing * 216) / 360)); // 54 pasos =1/4 de revolución Stearing =0; prevStearing =0; isStearing =falso; }} previousStearingMillis =currentStearingMillis; } // BOTONES RC RF ------------------ rfRemoteControlValue =checkRfRC (); if (rfRemoteControlValue) {switch (rfRemoteControlValue) {case RCleftbutton:// Botón izquierdo RC goleft (); descanso; case RCrightbutton:// Botón RC derecho goright (); descanso; case RCleft10button:// Left-10 RC button goleft10 (); descanso; case RCright10button:// Derecha + 10 botón RC goright10 (); descanso; }} // BOTONES ------------------------ HWButtonValue =checkHWButtons (); if (HWButtonValue) {switch (HWButtonValue) {case HWleftbutton:// Botón izquierdo (-1) HW if (isSetup ==false) {goleft (); } else {setupMinus (); } descanso; case HWrightbutton:// Botón derecho (+1) HW if (isSetup ==false) {goright (); } más {setupPlus (); } descanso; case HWpausebutton:// Botón de pausa HW gopause (); descanso; case HWsetupbutton:// Configurar el botón HW gosetup (); descanso; case HWleft10button:// Botón izquierdo (-10) HW goleft10 (); descanso; case HWright10button:// Derecha (+10) Botón HW goright10 (); descanso; }} // GPS NMEA ------------------ if (stringComplete ==true) {// recibió la sentencia nmea por el puerto serie RX bool ret; ret =nmeaExtractData (); inputString =""; stringComplete =falso; if (ret ==true) {RefreshDisplay (); }} // ALIMENTACIÓN DEL PERRO RELOJ ---------------- if (digitalRead (watchDogPin) ==LOW) {digitalWrite (watchDogPin, HIGH); } else {digitalWrite (watchDogPin, LOW); }} // leer sensores en multiplexervoid readMuxSensors () {float Vo =0; flotar n =0; flotador n1 =0; flotar v1ad =0; flotar v2ad =0; flotador corr =0; flotador R1 =10000; flotador logR2 =0; flotar R2 =0; flotador T =0; flotador c1 =1,009249522e-03; flotador c2 =2.378405444e-04; flotador c3 =2.019202697e-07; digitalWrite (MuxSelBit0Pin, BAJO); // 00 =Vbatt digitalWrite (MuxSelBit1Pin, LOW); n =analogRead (MuxIOPin); v1ad =n; n1 =(((10,00 * n) / 1023,00)); SensorVBatt =(n1 + ((n1 * 0.0) / 100)); // corrección arbitraria (inactiva =0.0%) digitalWrite (MuxSelBit0Pin, LOW); // 01 =Vres digitalWrite (MuxSelBit1Pin, HIGH); n =analogRead (MuxIOPin); v2ad =n; n1 =(((10,00 * n) / 1023,00)); SensorVRes =(n1 + ((n1 * 0.0) / 100)); // corrección arbitraria (inactiva =0.0%) digitalWrite (MuxSelBit0Pin, HIGH); // 10 =NTC Temp digitalWrite (MuxSelBit1Pin, LOW); Vo =analogRead (MuxIOPin); R2 =R1 * (1023,0 / Vo - 1,0); logR2 =log (R2); T =(1.0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2)); SensorTemp =T - 273,15; // Celsius n =(v1ad - v2ad); n1 =(n / 0,22) * 1000,00; SensormAmp =(((10.00 * n1) / 1023.00));} // extraer datos de nmea inputStringbool nmeaExtractData () {bool ret =false; // verdadero si nmea oración =$ GNRMC y CHKSUM válido if ((inputString.substring (0,6) =="$ GNRMC") &&(inputString.substring (inputString.length () - 4, inputString.length () - 2) ==nmea0183_checksum (inputString))) {y =0; para (s =1; s <11; s ++) {y =inputString.indexOf (",", y); switch (s) {caso 1:// tiempo z =inputString.indexOf (",", y + 1); if (z> (y + 1)) {nm_time =inputString.substring (y + 1, y + 2 + 1) + ":" + inputString.substring (y + 1 + 2, y + 4 + 1) + " :"+ inputString.substring (y + 1 + 4, y + 6 + 1); } y =z; descanso; caso 2:// validez z =inputString.indexOf (",", y + 1); if (z> (y + 1)) {nm_validez =inputString.substring (y + 1, y + 1 + 1); } y =z; descanso; caso 3:// latitud z =inputString.indexOf (",", y + 1); if (z> (y + 1)) {nm_latitude =inputString.substring (y + 1, y + 2 + 1) + "" + inputString.substring (y + 1 + 2, y + 10 + 1) + "' "; } y =z; descanso; caso 4:// norte / sur z =inputString.indexOf (",", y + 1); if (z> (y + 1)) {nm_latitude =nm_latitude + inputString.substring (y + 1, y + 1 + 1); } y =z; descanso; caso 5:// longitud z =inputString.indexOf (",", y + 1); if (z> (y + 1)) {nm_longitude =inputString.substring (y + 1, y + 3 + 1) + "" + inputString.substring (y + 1 + 3, y + 11 + 1) + "' "; } y =z; descanso; caso 6:// este / oeste z =inputString.indexOf (",", y + 1); if (z> (y + 1)) {nm_longitude =nm_longitude + inputString.substring (y + 1, y + 1 + 1); } y =z; descanso; caso 7:// nudos de velocidad z =inputString.indexOf (",", y + 1); if (z> (y + 1)) {nmf_knots =inputString.substring (y + 1, z) .toFloat (); t =roundOneDec (nmf_nudos); nm_knots =Cadena (t, 1) + "kn"; } y =z; descanso; caso 8:// curso verdadero z =inputString.indexOf (",", y + 1); if (z> (y + 1)) {nmf_truecourse =inputString.substring (y + 1, z) .toFloat (); d =nmf_truecourse; nm_truecourse =d; } y =z; descanso; caso 9:// fecha z =inputString.indexOf (",", y + 1); if (z> (y + 1)) {nm_date =inputString.substring (y + 1, y + 2 + 1) + "/" + inputString.substring (y + 1 + 2, y + 4 + 1) + " /20"+inputString.substring(y+1+4,y+6+1); } y =z; descanso; caso 10:// las sentencias se rompen; predeterminado:// sentencias se rompen; }} si ((isfirstfix ==true) || (ispause ==true)) {nm_routetofollow =nm_truecourse; nmf_routetofollow =nmf_truecourse; isfirstfix =falso; } ret =verdadero; } return ret;} // aumenta (+) el valor del parámetro durante setupvoid setupPlus () {switch (SetupParameter) {caso 2:// intervalo StearingInterval =(StearingInterval + 100); if (StearingInterval> 5000) {StearingInterval =5000; } descanso; caso 3:// min. para mover StearingMinToMove =(StearingMinToMove + 1); if (StearingMinToMove> 20) {StearingMinToMove =20; } descanso; caso 4:// max. mover StearingMaxMove =(StearingMaxMove + 1); if (StearingMaxMove> 45) {StearingMaxMove =45; } descanso; caso 5:// coeficiente StearingCoeffMove =(StearingCoeffMove + 0.1); if (StearingCoeffMove> 4) {StearingCoeffMove =4; } descanso; } retraso (200); RefreshDisplay ();} // disminuye (-) el valor del parámetro durante setupvoid setupMinus () {switch (SetupParameter) {caso 2:// intervalo StearingInterval =(StearingInterval - 100); if (StearingInterval <1000) {StearingInterval =1000; } descanso; caso 3:// min. para mover StearingMinToMove =(StearingMinToMove - 1); if (StearingMinToMove <0) {StearingMinToMove =0; } descanso; caso 4:// max. mover StearingMaxMove =(StearingMaxMove - 1); if (StearingMaxMove <10) {StearingMaxMove =10; } descanso; caso 5:// coeficiente StearingCoeffMove =(StearingCoeffMove - 0.1); if (StearingCoeffMove <0.1) {StearingCoeffMove =0.1; } descanso; } retraso (200); RefreshDisplay ();} // control del motor (+) =avance (-) =retrocesovoid gomotor (int stepsToMove) {digitalWrite (motorsABenablePin, HIGH); motor.step (stepsToMove); digitalWrite (motorsABenablePin, LOW);} // actualizar datos en displayvoid RefreshDisplay () {if (isSetup ==false) {// --------- normal lcd.clear (); lcd.setCursor (0,0); lcd.print ("R" + nm_routetofollow); lcd.write (0xDF); lcd.print ("H" + nm_verdadero); lcd.write (0xDF); if (ispause ==true) {lcd.print ("DETENER"); } else {if (Stearing> 0) {lcd.print ("+"); } if (Stearing ==0) { lcd.print(" "); } if (Stearing <0) { lcd.print(" "); } lcd.print(int(Stearing)); } lcd.setCursor(0,1); lcd.print(nm_time+" "+nm_knots); } if (isSetup ==true) { //-----------setup lcd.clear(); lcd.setCursor (0,0); lcd.print("setup:"); switch (SetupParameter) { case 1://display sensors readMuxSensors(); lcd.print("V="); lcd.print(SensorVBatt); lcd.setCursor (1,1); lcd.print("mA="); lcd.print(int(SensormAmp)); lcd.print (""); lcd.print(int(SensorTemp)); lcd.write(0xDF); lcd.print("C"); descanso; case 2://interval lcd.print("interval"); lcd.setCursor (7,1); lcd.print(StearingInterval); lcd.print(" mSec"); descanso; case 3://min. to move lcd.print("minimum"); lcd.setCursor (7,1); lcd.print(StearingMinToMove); lcd.write(0xDF); descanso; case 4://max. move lcd.print("max"); lcd.setCursor (7,1); lcd.print(StearingMaxMove); lcd.write(0xDF); descanso; case 5://coefficient lcd.print("coeffic."); lcd.setCursor (7,1); lcd.print(StearingCoeffMove); lcd.print(" x "); lcd.write(0xDF); descanso; } }}/* SerialEvent occurs whenever a new data comes in the hardware serial RX. This routine is run between each time loop() runs, so using delay inside loop can delay response. Multiple bytes of data may be available.*/void serialEvent() { while (Serial.available()) { char inChar =(char)Serial.read(); inputString +=inChar; // if the incoming character is a newline, set a flag so the main loop can // do something about it if (inChar =='\n') { stringComplete =true; } } }//calculate checksum of nmea sentenceString nmea0183_checksum(String nmea_data) { int crc =0; String chSumString =""; int i; // ignore the first $ sign, checksum in sentence for (i =1; i <(nmea_data.length()-5); i ++) { // remove the - 5 if no "*" + cksum + cr + lf are present crc ^=nmea_data[i]; } chSumString =String(crc,HEX); if (chSumString.length()==1) { chSumString="0"+chSumString.substring(0,1); } chSumString.toUpperCase(); return chSumString;}//check RC which button is pressedint checkRfRC() { int n =0; int res =0; n =analogRead(rfRemoteControlPin); if ((n>350) and (n<460)) { // button A res =RCleftbutton; } if ((n> 90) and (n<190)) { // button B res =RCrightbutton; } if ((n>540) and (n<640)) { // button C res =RCleft10button; } if ((n>225) and (n<325)) { // button D res =RCright10button; } return res; }//check HW which button is pressedint checkHWButtons() { int n =0; int res =0; n =analogRead(ButtonsPin); //Serial.println(n); if ((n>465) and (n<565)) { // button left res =HWleftbutton; } if ((n>290) and (n<390)) { // button right res =HWrightbutton; } if ((n>130) and (n<220)) { // button pause res =HWpausebutton; } if ((n>625) and (n<725)) { // button setup res =HWsetupbutton; } if ((n>975) and (n<1075)) { // button left-10 res =HWleft10button; } if ((n>800) and (n<900)) { // button right+10 res =HWright10button; } return res; }void gosetup() { // setup button if (isSetup ==false) { SetupParameter =1; isSetup =true; } else { if (SetupParameter <5) { SetupParameter ++; } else { if (prev_StearingInterval !=StearingInterval || prev_StearingMinToMove !=StearingMinToMove || prev_StearingMaxMove !=StearingMaxMove || prev_StearingCoeffMove !=StearingCoeffMove) { lcd.clear(); lcd.setCursor (0,0); lcd.print("updating... "); retraso (1000); goupdateEEPROM(); if (EEerr) { lcd.print("E="); lcd.print(EEerr); retraso (1000); } prev_StearingInterval =StearingInterval; prev_StearingMinToMove =StearingMinToMove; prev_StearingMaxMove =StearingMaxMove; prev_StearingCoeffMove =StearingCoeffMove; } isSetup =false; } } NewTone (speakerPin,2000); retraso (200); noNewTone(); RefreshDisplay();}void goupdateEEPROM() { EEaddress =0; //id1 EEdata[0] =EEid1; EEbytedata =EEid1; writeEEPROM (EEdisk, EEaddress, EEbytedata); EEaddress =1; //id2 EEdata[1] =EEid2; EEbytedata =EEid2; writeEEPROM (EEdisk, EEaddress, EEbytedata); memcpy(bStearingInterval, &StearingInterval, sizeof(int)); memcpy(bStearingMinToMove, &StearingMinToMove, sizeof(int)); memcpy(bStearingMaxMove, &StearingMaxMove, sizeof(int)); memcpy(bStearingCoeffMove, &StearingCoeffMove, sizeof(float)); memcpy(EEdata+2,bStearingInterval,sizeof(int)); memcpy(EEdata+4,bStearingMinToMove,sizeof(int)); memcpy(EEdata+6,bStearingMaxMove,sizeof(int)); memcpy(EEdata+8,bStearingCoeffMove,sizeof(float)); for (s =2; s  360) { nmf_routetofollow =1; } d=nmf_routetofollow; nmf_routetofollow=d; nm_routetofollow=d; NewTone (speakerPin,800); retraso (200); noNewTone(); } else { NewTone (speakerPin,1000); retraso (50); noNewTone(); } RefreshDisplay();}void goright10() { // right 10x button/RC if (ispause ==false) { for (s =1; s <11; s ++) { nmf_routetofollow ++; if (nmf_routetofollow> 360) { nmf_routetofollow =1; } } d=nmf_routetofollow; nmf_routetofollow=d; nm_routetofollow=d; NewTone (speakerPin,800); retraso (200); noNewTone(); } else { NewTone (speakerPin,1000); retraso (50); noNewTone(); } RefreshDisplay();}void gopause() { // pause button/RC if (ispause ==true) { ispause=false; digitalWrite(ledpausePin, HIGH); NewTone (speakerPin,50); retraso (200); NewTone (speakerPin,200); delay(800); noNewTone(); } else { ispause=true; digitalWrite(ledpausePin, LOW); NewTone (speakerPin,200); retraso (200); NewTone (speakerPin,50); delay(800); noNewTone(); } RefreshDisplay();}// reading eeprombyte readEEPROM (int diskaddress, unsigned int memaddress) { byte rdata =0x00; Wire.beginTransmission (diskaddress); Wire.write (memaddress); if (Wire.endTransmission () ==0) { Wire.requestFrom (diskaddress,1); if (Wire.available()) { rdata =Wire.read(); } else { EEerr =1; //"READ no data available" } } else { EEerr =2; //"READ eTX error" } Wire.endTransmission (true); return rdata;}// writing eepromvoid writeEEPROM (int diskaddress, unsigned int memaddress, byte bytedata) { Wire.beginTransmission (diskaddress); Wire.write (memaddress); Wire.write (bytedata); if (Wire.endTransmission () !=0) { EEerr =3; //"WRITING eTX error" } Wire.endTransmission (true); retraso (5); }// round zero decimalfloat roundZeroDec(float f) { float y, d; y =f*1; d =y - (int)y; y =(float)(int)(f*1)/1; if (d>=0.5) { y +=1; } else { if (d <-0.5) { y -=1; } } return y;}// round one decimalfloat roundOneDec(float f) { float y, d; y =f*10; d =y - (int)y; y =(float)(int)(f*10)/10; if (d>=0.5) { y +=0.1; } else { if (d <-0.5) { y -=0.1; } } return y;}// round two decimalfloat roundTwoDec(float f) { float y, d; y =f*100; d =y - (int)y; y =(float)(int)(f*100)/100; if (d>=0.5) { y +=0.01; } else { if (d <-0.5) { y -=0.01; } } return y;}
WatchDog sketch (for Nano)Arduino
/* * This sketch is a Watchdog to keep CLIENT under control, on Arduino NANO 3.0 by Marco Zonca * CLIENT must feed Whatcdog sooner then feedingInterval otherwise will be forced to restart * */const int feedingPin =14;const int ledPin =15;const int restartPin =16;const int buzzerPin =17;const long ledInterval =1000;const long feedingInterval =2500;const long timeForClientStart =16000;int ledState =LOW;int previousFeedingState =LOW;int feedingState =LOW;unsigned long previousLedMillis =0;unsigned long previousFeedingMillis =0;void setup() { digitalWrite(restartPin, HIGH); // LOW will force CLIENT to restart pinMode(ledPin, OUTPUT); pinMode(buzzerPin, OUTPUT); pinMode(restartPin, OUTPUT); pinMode(feedingPin, INPUT); delay(timeForClientStart); // let time to CLIENT to start...}void loop() { unsigned long currentMillis =millis(); // BLINK LED ------------------- if (currentMillis - previousLedMillis>=ledInterval) { previousLedMillis =currentMillis; if (ledState ==LOW) {ledState =HIGH; } else {ledState =LOW; } digitalWrite (ledPin, ledState); } // CHECK THE FEEDING ------------------- feedingState =digitalRead(feedingPin); // CLIENT must set pin HIGH -> LOW frequently to prove it's alive if (feedingState ==HIGH) { if (previousFeedingState ==LOW) { previousFeedingMillis =currentMillis; } previousFeedingState =HIGH; } else { previousFeedingState =LOW; } if (currentMillis - previousFeedingMillis> feedingInterval) { // CLIENT is sleeping ledState =HIGH; digitalWrite(ledPin, ledState); tone(buzzerPin,1500); retraso (500); digitalWrite(restartPin, LOW); //restart CLIENT tone(buzzerPin,1500); retraso (500); digitalWrite(restartPin, HIGH); tone(buzzerPin,1500); delay(timeForClientStart); // let CLIENT time to restart... noTone(buzzerPin); currentMillis =millis(); previousFeedingState =LOW; previousFeedingMillis =currentMillis; previousLedMillis =currentMillis; }} 

Piezas y carcasas personalizadas

23lm-stepper-plate-v2_PlvJaff9Hl.step 23lm-stepper-pulley-56_UhsbaWbiBt.step

Esquemas


Proceso de manufactura

  1. Sistema de sensor de movimiento por infrarrojos de bricolaje para Raspberry Pi
  2. Construye un sistema de recuperación de paracaídas balístico para tu dron
  3. ¿Es un sistema de monitoreo continuo adecuado para usted?
  4. Cambiadores automáticos de herramientas para robots
  5. ¿Su sistema está listo para IoT?
  6. Cortadores poligonales para tornos automáticos
  7. Torno automático CNC para piezas de precisión
  8. Sistema de propulsión para vuelo hipersónico
  9. Principio de funcionamiento del sistema de transmisión manual y automática.
  10. Comprender el sistema de transmisión automática
  11. Comprender el sistema de lubricación automática