Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Autopilot für Segelboote (automatisches Steuersystem)

Komponenten und Verbrauchsmaterialien

Arduino UNO
× 1
Arduino Nano R3
× 1

Über dieses Projekt

Vorwort:

Ich liebe es alleine zu segeln, denn wenn ein Mann mit seinem Segelboot auf dem Meer ist, hat er alles, was er braucht, um sich auf ein höheres Niveau zu entwickeln. Bei schlechtem Wetter auf rauer See zu segeln kann sehr hart sein, aber wenn er Tage mit gutem Wetter mit Sonne und schönem Wind wählt, wird der Spaß am Maximum sein.

Glück bedeutet unendliche Horizonte, perfekte Sporttechnik, optimale Auswahl, aber auch menschliche Dinge als ein gutes Getränk und ein leckeres Sandwich! Genau in dieser Zeit kommt Autopilot zu Hilfe:Es funktioniert, anstatt dass Sie währenddessen um 17:00 Uhr Tee &Kekse auf dem Meer haben. :-)

Was Autopilot für Sie tun kann:

Ein Segelboot hat keinen Motor und kann nicht einen programmierten Weg vom Hafen zum Strand, dann zum Angelplatz, um den Leuchtturm und zurück fahren, ganz allein, es kann nicht.

Die ganze Arbeit wird vom Segler gemacht, wir müssen es an dieser Stelle verstehen:Segel trimmen, Wetter und Windquelle/Geschwindigkeit unter Kontrolle bringen, Seile härten oder loslassen, Verkehr mit anderen Booten beachten, Richtung und Steuerung bestimmen... Wann entscheidet sich der Matrose für eine Pause, sagen wir mal 10 Sekunden oder ein paar Minuten länger (die berühmte "Tea Time"), schaltet er den Autopiloten ein. Sein GPS erfasst in Sekundenschnelle Position, Geschwindigkeit und Richtung des Bootes und kann die Richtung (Route) beibehalten. Das Steuersystem, ein mit dem Ruder verbundener Knüppel, der normalerweise von erfahrenen Sailor-Händen bewegt wird, wird jetzt vom Autopiloten durch den Schrittmotor gesteuert, der über Riemenscheiben und Seile damit verbunden ist.

Steuern Sie das Ruder ist eine kontinuierliche Arbeit der Fein- oder Grobeinstellung. Kleiner (leichter) ist das Boot und größer werden die Richtungsänderungen, die es beeinflussen:Meereswellen, Richtung und Druck des Windes, Gewichtsverlagerung an Bord durch Seglerbewegungen, Meeresströmungen. Aber der Sailor ist immer wach, auch wenn der Autopilot eingeschaltet ist, und nimmt Änderungen an der tatsächlichen Route über die Fernbedienung vor :Es gibt 4 Tasten mit der Bezeichnung +1 -1 +10 -10, für kleine oder große Gradänderungen, zum Erhöhen oder Verringern des Wertes. Diese Schaltflächen sind auf dem Autopiloten vorhanden auch die grünen (rechts) und die roten (links). Die blaue Taste (Mitte) dient zum Aktivieren oder Deaktivieren des Autopiloten, der Pause. Es ist auch eine schwarze Schaltfläche zum Einrichten von Parametern im Gedächtnis.

Die Schaltung:

Die Hauptverarbeitung erfolgt durch MCU Arduino Uno . Die andere MCU, Arduino Nano , ist der Watchdog:Ich weiß, dass es eine Art Watchdog im Uno gibt, aber ich habe es gerne mit einem unabhängigen externen Mikrocontroller gemacht, es ist ein Lebenstraum, den ich erfüllt habe, ich bin jetzt glücklich! Uno muss Nano über Pin 3 -> A0 speisen, indem es High / Low, 5 / 0 Volt, mindestens einmal alle 2,5 Sekunden (feedingInterval) setzt; Wenn nicht, bedeutet dies, dass der Uno "schläft" oder "blockiert" ist und Nano Uno zurücksetzt ... Es ist noch nie passiert, können Sie das glauben?

Es wird als beliebtes Display verwendet in Verbindung mit einem i2c-Schaltungswandler beide zusammen gelötet, schließlich mit nur 4 Drähten, um digitale Pins für die Kommunikation mit Uno erheblich zu schonen. Auch die Verbindung von Tasten und Fernbedienung wird durch Widerstandsspannungsteiler erreicht, um das Ziel zu erreichen, so wenig MCU-Ports wie möglich zu verwenden; Ich habe 1% Präzisionswiderstände gewählt, die analogen Vergleichswerte sollten zwischen Werten liegen, die ich in den Code eingegeben habe; Falls einige Schaltflächen nicht erkannt werden, weil Sie andere Arten von Widerständen wählen, nehmen Sie einfach einige Änderungen an den Konstanten vor (ändern Sie den Code bei "checkRfRC()" und "checkHWButtons()"). Die RF 433Mhz Remote Control (RC) Schaltung funktioniert gut; um die Reichweite und die Erfolgschancen zu verbessern, habe ich eine Spulenantenne hinzugefügt, die Sie mit einem Stück Kupferdraht selbst herstellen können; Ich habe es in 10 Metern Entfernung getestet, aber ich denke, es kann sogar bei 20 Metern oder mehr funktionieren, mehr als genug, wenn man bedenkt, dass das Zielsegelboot, mit dem ich den Autopiloten getestet habe, nur 4,20 Meter lang war.

Für das GPS-Gerät Ich habe anfangs einen guten EM406A verwendet, aber leider habe ich festgestellt, dass er unter einem Week-Rollover-Bug litt, er war zu alt, dann musste ich ihn gegen einen hervorragenden und beliebten Beitian BN-220T austauschen. Stellen Sie es mit seiner Konfigurationssoftware bitte so ein, dass es 2 Mal pro Sekunde (2Hz) "ausspuckt", nur der notwendige "$GNRMC" NMEA-Seriensatz. Das GPS sendet (TX) serielle Daten an Pin 0 (RX) von Uno. Die Daten enthalten alle Navigationsdaten, die zur Berechnung der vom Motor auszuführenden Korrektur verwendet werden:Datum, Uhrzeit, Breiten- und Längengrad der Position, wahrer Kurs, Geschwindigkeit und Gültigkeit der Satellitenfixierung. Aufgrund der Tatsache, dass die IDE-Programmierung von Arduino auch den Anschluss Pin 0 (RX) verwendet, denken Sie daran, das GPS während dieses Vorgangs vorübergehend zu trennen...

Ein weiterer Traum von mir war, ein EEPROM zu verwenden . Der IC 2404 ist ein wunderschöner 512 Byte i2c integrierter Schaltkreis, den ich verwendet habe, um in diesem Speicherchip einige Parameter für Schrittmotorbewegungen zu lesen / zu schreiben, die ich später im Abschnitt "Software" erklären werde.

Komponentenliste:

  • Arduino Uno als MCU
  • Arduino Nano als WatchDog
  • Beitian BN-220T GPS
  • Schrittmotor, Modell 23LM, 54 Schritte =1/4 Umdrehung
  • Controller Keyes L298 für Motor
  • RF433Mhz RC XD-YK04 + 4 Tasten Fernbedienung + Spulenantenne
  • 6 Tasten normal offen (2xRot, 2xGrün, 1xSchwarz und 1xBlau)
  • Schalter zum Ein-/Ausschalten (Weiß)
  • Weiblich + Stecker 6-Pin-Rundstecker für externen Schrittmotor
  • Summer
  • Display LCD1602 2x16 Zeichen + i2c-Wandlerschaltung
  • 3 LEDs (rot, blau und gelb))
  • IC 24c04 i2c eeprom
  • IC 4051-Multiplexer
  • Akku LiPo 2s 7,4V 2600mA
  • IC 7805 Spannungsregler + Kühlkörper
  • Thermistor NTC MF52-103 10k
  • Rückstellbare Sicherung 2A
  • 6x 1N4148 Dioden (D1-D6)
  • Widerstände auf Stromschild (R1-R4=10k, R5=100k)
  • Widerstände auf Autopilot-Schild (R1=330, R2=1k, R3=2k, R4=5.1k, R5=1k, R6/R7/R14=330, R8-R13=10k, R15=10M)
  • Kondensatoren (C1=470uF 16v, C2=100n)
  • 2W 0,22 Ohm Widerstand (R6)
  • Männliche Pins
  • Weibliche lange Stiftleisten
  • Gehäuse transparent und "wasserdicht"

Es gibt ein paar Sensoren auf der Schaltung alle mit Arduino Uno verbunden mit Hilfe des IC 4051 Multiplexer . Es ist ein Thermistor um die Temperatur des Heizleiters des Spannungsreglers zu kontrollieren, einen 2W-Widerstand und 4x10k als Spannungsteiler zur Berechnung von Ampere als Leistungsaufnahme der ganzen Schaltung. Auch die Batteriespannung wird unter Kontrolle gebracht:LiPo sind bekanntermaßen kritisch, wenn einzelne Elemente unter 3,3 V entladen werden; diese Schaltung hat zwei Elemente (2S) LiPo in einem Gehäuse, bei niedriger Spannung (unter 7,0V) den Summer informiert Sie mit kurzen kurzen Pieptönen. Warten Sie nicht zu lange mit dem Ausschalten und laden Sie bald wieder auf! Die LEDs :gelbes Blinken mit 1 Hz zeigt an, dass der WatchDog funktioniert; die blaue ist eingeschaltet, wenn der Autopilot eingeschaltet ist, und ausgeschaltet, wenn er pausiert ist; Die rote LED blinkt, wenn eine der Tasten der Fernbedienung gedrückt wird.

Alle Schaltungen funktionieren mit 5,0 V, versorgt von LiPo 2S 7,4 V 2600 mA/h Batterie und IC 7805 Spannungsregler . Der Strom sollte nicht größer als 800 mA sein, normalerweise liegt er jedoch bei 100-450 mA. Bitte setzen Sie einen Wärmeableiter auf . Der Thermistor wird darauf platziert und der Summer piept, wenn die Temperatur 50°C überschreitet.

Die PCB-Leiterplatten und die Bestückung:

Wird für Single-Face-Leiterplatten verwendet Aus diesem Grund musste ich ein paar Drahtbrücken (die gepunkteten) einfügen, um Routen für ganze Schaltungen zu lösen. Hier werden die Bauteilgesichter angezeigt, aber unten haben Sie alle Dateien, Bauteile und Lötgesichter, gespiegelt, zum Herunterladen und Ausdrucken mit einem Laserdrucker auf "gelben" oder "blauen" Blättern. Ich habe die gelben verwendet, aber sie sagen, die blauen sind besser (aber der Preis ist deutlich höher). Denken Sie beim Drucken daran, die Tonerspareinstellungen zu deaktivieren, verwenden Sie stattdessen eine Auflösung von 1200 dpi, um ein tiefes, echtes Schwarz zu erhalten. Der Tonertransferprozess von Magic Sheets auf PCBs erfolgt durch die Verwendung eines heißen Bügeleisens... Die beidseitige Bedruckung, auch auf der Bauteilseite, macht die Positionierung von Artikeln leicht erkennbar und macht das Projekt sogar "professionell".

Beide PCBs sind so dimensioniert, dass sie übereinander Arduino Uno als Stapel passen :zuerst Power-Einheit, dann Autopilot-Einheit insgesamt.

Meine Wahl war, alle Dinge zusammenzufügen, PCBs, MCUs, RC, Motortreiberschaltung, Batterie, GPS, Tasten, Schalter, Drähte, Stecker usw. und dachte daran, sie eines Tages wiederzuverwenden:Ich habe sie nicht zusammengelötet, ich gebraucht Überschriften und beliebte Dupont-Kabel/-Verbindungen stattdessen. Es gibt dann ungefähr 200 ungelötete Verbindungen, das bedeutet, dass von Zeit zu Zeit unerwartete und unerwünschte Fehlfunktionen oder ein anderes Verhalten der Schaltung auftreten können, das ist normal. Vorschlag ist, alles zu löten für eine stabilere Schaltung!

Parameter Setup und Anzeige der Sensorwerte:

Drücken der schwarzen Taste an der Seite des Feldes betritt es in den Einrichtungsmodus; dies kann auch während der aktiven Navigation erfolgen, es ist nicht erforderlich, zuerst Pause einzugeben. Die 1. Seite des Displays zeigt Batteriespannung (V=7,83), Stromverbrauch (mA=177) und Temperatur des Thermistorsensors in der Nähe des Kühlkörpers (38°C); durch wiederholtes Drücken der schwarzen Taste gelangen Sie zu den nächsten Seiten; auf der 2., 3., 4. und 5. Seite werden die unten aufgeführten Parameter angezeigt und Sie können diese Werte mit den Tasten -1 und +1 ändern. Auf der 6. Seite wird "Aktualisieren..." angezeigt, wenn Sie etwas geändert haben, werden die Werte im EEPROM-Speicher gespeichert.

  • Intervall: d.h. 2000 ms, ist die Zeit zwischen einem Versuch und dem anderen durch den Schrittmotor, um den Kurs "H" auf die Route "R" wiederherzustellen, indem der Ruderhebel nach rechts oder links bewegt wird;
  • Minimum: d.h. 2°, ist die minimale Gradabweichung außerhalb der Route, damit der Autopilot eingreifen kann; bis zu diesem Wert bleibt das Ruder stabil in Mittelstellung;
  • Max: d.h. 40°, ist die maximale Lenkungsänderung auf einmal durch den Schrittmotor; wenn die Berechnung für eine Änderung von 50° erfolgt, bewegt sich der Stepper in Wirklichkeit nur um 40°;
  • Koeffizient: d.h. 1,50 x °, ist der Koeffizient für die jeweilige Lenkänderung; wenn die Berechnung für eine 40°-Änderung erfolgt, bewegt sich der Schrittmotor in Wirklichkeit um (40 x 1,50) =60°;

Diese Parameter sind notwendig, für die Feinabstimmung des Autopiloten wenn auf dem Segelboot installiert. Ansprechverhalten, Empfindlichkeit und Laufruhe hängen vom Durchmesser der Riemenscheiben, der Anzahl der Riemenscheiben, dem Durchmesser der Hauptriemenscheibe des Schrittmotors, der Empfindlichkeit des Ruders, der Länge des daran angeschlossenen Ruderknüppels usw. ab. Lassen Sie alles installieren und versuchen Sie Erfahrungen an Bord zu sammeln. Wähle für alle Testphasen natürlich einen sonnigen schönen Tag mit leichtem Wind!

So funktioniert es "live":

Sie navigieren auf dem Meer, auf dem See oder einfach nur um den Hafen herum. Es ist Tea Time und Ihre Cola und Ihr Lieblingssandwich warten in der Tasche. Hier sind wir:Autopilot wechseln an und lassen Sie es Satelliten-GPS-Fix durchführen, Sie sollten jetzt auf dem Display die aktuelle Geschwindigkeit in Knoten, die Uhr und die Kursrichtung ablesen, dh H270° (R =zu verfolgende Route, H =aktueller Kurs) in Grad (denken Sie daran 180° =Süd, 270° =Westen, 360° oder 0°=Norden und 90°=Osten). Die R- und H-Werte sind im Pause-Modus gleich (STOP wird angezeigt). Verbinden Sie nun das Steuerseil vom Schrittmotor mit dem Ruderknüppel und drücken Sie die blaue Taste, um die Autopilot-Steuerung zu starten; An diesem Punkt hält der Autopilot R =Routenrichtung und kontrolliert, was mit H =Kurs passiert. Überschriftsnummer ändert sich sicher , langsam oder schnell, abhängig von den Wetterbedingungen, über die wir bereits gesprochen haben. Der Autopilot versucht dann, die R=Route-Richtung wiederherzustellen Korrekturen vorzunehmen, z. B. -10°, +5° usw., bis der H-Wert dem R-Wert entspricht . Sie können einige Änderungen an der Route vornehmen und die Nummer mit den roten und grünen Tasten am Gerät (-1 -10 +1 +10) oder über die Fernbedienung ändern. Um die Kontrolle zurückzugewinnen von die Steuerung Sie müssen nur die blaue Taste Pause drücken, das Seil vom Ruderknüppel trennen und die Arbeit mit Ihren Händen fortsetzen. Gut gemacht.

Softwareseite:

Der Code ist ziemlich lang, aber ich hoffe, er ist klar genug, um leicht verständlich zu sein. Auf jeden Fall würde ich erklären, wie es läuft. Der Sketch verwendet etwa 65 % des Programms und etwa 45 % des Speichers. Selbst bei der Verwendung der String-Klasse, hauptsächlich für die Manipulation von seriellen NMEA-Sätzen, ist der gesamte Ausarbeitungsfluss stabil und solide; es verwendet "serialEvent()", um zweimal pro Sekunde Daten vom GPS zu empfangen , ruft dann "nmeaExtractData()" auf und überprüft schließlich das Datenpaket mit "nmea0183_checksum()", um die Datenintegrität sicherzustellen. Wenn Sie ein anderes GPS-Modell verwenden, stellen Sie sicher, dass die Sätze die gleiche Struktur haben oder müssen Sie hier einige Änderungen vornehmen . Beispiel:EM406A verwendet die Paket-ID "$GPRMC" , BT220 verwendet stattdessen "$GNRMC" ... nur eine kleine Namensänderung ... Ein nützlicher Link kann Ihnen beim Prüfsummentest helfen:https://nmeachecksum.eqth.net - Hier ein Beispiel für einen vollständigen NMEA-Satz, er enthält :ID, Zeit, Gültigkeit, Breitengrad, Längengrad, Geschwindigkeit, wahrer Kurs, Datum, Abweichung und Prüfsumme.

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

Während "Setup()" wird das EEPROM überprüft :falls neu oder unbekannt, wird es initialisiert (formatiert). Parameter im Speicher werden als Byte gelesen/geschrieben:0=0x29, 1=0x00, 2-3=Intervall, 4-5=min, 6-7=max, 8-11=Koeffizient (Byte, Byte, Int, Int, schweben). Ich bin mit EEPROM r/w-Operationen vorsichtig umgegangen, vielleicht zu viel defensiv... Sensoren werden alle 10 Sekunden überprüft durch "readMuxSensors()" vom Multiplexer und kann einen Alarm auslösen, wenn die Batterie schwach ist oder die Temperatur hoch ist. Die Auflösung des Stromverbrauchs ist gering, Schritte von ca. 40mA. Hardware und RC-Tasten werden laufend überprüft; was sie tun, hängt vom booleschen Wert "IsSetup" sowie der Anzeige von "RefreshDisplay()" ab . Der Kern des Codes ist der Abschnitt STEERING CONTROL, der die Funktion "gomotor()" aufruft, um den Stepper hin und her zu bewegen; ja, es kann das Ruder um 10° nach rechts bewegen und nach dem Intervallwert bewegt es sich nach einer neuen Berechnungsrunde wieder auf die Null-Ruderposition und so weiter. Wie bereits erwähnt, wird auch während des Setups Lenkarbeit geleistet, da sie nur wenige Tasten und das Anzeigeverhalten betrifft. Whatchdog-Fütterung ist sehr einfach, aber wichtig:einfach seinen Pin so schnell wie möglich an- und ausschalten.

So installieren Sie es auf einem Segelboot:

Wie in der Abbildung unten gezeigt, habe ich mich entschieden, den Autopiloten und den Schrittmotor am Heck zu platzieren, beide gut mit Schrauben usw. befestigt; Ein Seil mit 6 mm Durchmesser beginnt an der Hauptrolle des Motors und geht um zwei andere Rollen, die auf beiden Seiten platziert sind. Diese beiden Riemenscheiben sollten mit Hilfe von zwei Bungee-Ringen am Boot "fixiert" werden, um das Seil leicht unter Spannung zu halten. An dieser Stelle müssen Sie schließlich entscheiden, wie Sie das Seil mit dem Ruderstock verbinden (temporäre Verbindung); Es muss verbunden sein, während Sie möchten, dass Autopilot in Aktion ist, einfach zu verbinden und einfach zu trennen. Halten Sie das Autopilot-System von Wasser fern! :-)

Neuigkeiten und Updates:

  • 10.05.2020, hinzugefügt zum Herunterladen von .STEP 3D-CAD-Projektdateien für die Schrittrolle (von mir) und die Montageplatte (von Andrew Barney) und ein 3D-Vorschaubild davon.

Haftungsausschluss und Warnungen:

Sagen wir, das ist ein Spiel, das wir hier spielen, nichts zu ernst nehmen! Vor ein paar Jahren habe ich eine lange Reise, 16 Monate, um die Welt auf einem Segelboot gemacht. Wir haben ausgiebig mit einem echten Autopiloten navigiert (NICHT DAS EINS!) bei jedem Wetter, auch bei schlechtem Wetter. Ein echter Autopilot ist etwas sehr stark Sowohl Hardware als auch Software müssen Sie vertrauen viel. Dieser Arduino Autopilot stattdessen ist ein fantastisches Spiel mit und zu verbringen Sie Zeit zum Spaß.

Viel Spaß!

Marco Zonca

Code

  • Autopilot-Skizze (für Uno)
  • WatchDog-Skizze (für Nano)
Autopilot-Skizze (für Uno)Arduino
/* Diese Skizze dient als Autopilot für kleine Segelboote, von Marco Zonca, 2019 Arduino UNO als CPU, Arduino Nano als Watchdog, GPS BT-220 nmea, Schrittmotor + Controller, rf433Mhz RC, 6 Tasten, Summer, i2c Display, 2 LEDs, i2c 24c04 Eeprom, Mux 4051 für Sensoren, Lipo 2s 7,4V 2600mA, 7805 Spannungsregler, Thermistor;*/#include #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/yyyy";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;// folgende Parameter sind die Standardwerte, können aber gelesen/geschrieben werden eeprom// eeprom wird initialisiert wenn bei Adressen 0 und 1 der Inhalt unterschiedlich ist Adresse len Typ Anmerkungen// 0-255 Byte bei 0x50 EEdisk, 256-512 Byte bei 0x51 (nicht verwendet) ---------- -------------------------------------------------- ---// 0 1B byte 01001001 (0x29 als Autopilot-Projekt-ID1)// 1 1B byte 00000000 (0x00 " " id2)int StearingInterval =2000; // Millis zwischen Try und Back 2 2B int StearingInterval 1000-5000 Schritte 100int StearingMinToMove =2; // Kompass_Grad 4 2B int StearingMinToMove 0-20 Schritte 1int StearingMaxMove =40; // Kompass_Grad 6 2B int StearingMaxMove 10-45 Schritte 1float StearingCoeffMove =1.5; // verwendet als (compass_degrees * coeff) 8 4B float StearingCoeffMove 0.1-4 Schritte 0.1// 12 free//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 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 motorStepsPerRevolution =200; // 200 für Modell 23LM, 54 Schritte =1/4 UmdrehungLiquidCrystal_I2C lcd (0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);Schrittmotor (motorStepsPerRevolution, 9, 10, 11, 12 ); Einrichtung ungültig () { Serial.begin (4800); lcd.begin(16,2); Wire.begin(); motor.setSpeed(60); inputString.reserve(200); pinMode (MotorenABenablePin, OUTPUT); pinMode (MuxSelBit0Pin, AUSGANG); pinMode (MuxSelBit1Pin, AUSGANG); digitalWrite (MotorenABenablePin, LOW); digitalWrite (MuxSelBit0Pin, LOW); digitalWrite (MuxSelBit1Pin, LOW); pinMode (ledpausePin, AUSGANG); pinMode (watchDogPin, AUSGANG); digitalWrite (ledpausePin, LOW); digitalWrite (watchDogPin, LOW); // EEPROM lesen + überprüfen (Formatierung, wenn neu (oder nicht identifiziert)) lcd.clear (); lcd.setCursor(0,0); lcd.print("Speicherüberprüfung..."); lcd.setCursor(0,1); for (s =0; s =CheckSensorsInterval) { readMuxSensors(); if ((SensorVBatt <=7.0) || (SensorTemp>
=50)) {lcd.clear(); lcd.setCursor(0,0); lcd.print("Alarmsensoren!"); lcd.setCursor(1,1); lcd.print("V="); lcd.print (SensorVBatt); lcd.print(" "); lcd.print (int (SensorTemp)); lcd.write(0xDF); lcd.print("C"); NewTone (LautsprecherPin,10); Verzögerung (1000); noNewTone(); } prevCheckSensorsMillis =currCheckSensorsMillis; } // STEARING CONTROL ---------------- currentStearingMillis =millis (); if (currentStearingMillis - previousStearingMillis>=StearingInterval) { if (isStearing ==false &&ispause ==false) { // versuchen Sie es (Stearing verschieben) calcmove =nmf_routetofollow - nmf_truecourse; if (Calcmove <(-180)) {Calcmove =Calmove + 360; aufrechtzuerhalten. Sonst { if (calcmove> (+180)) {Calcmove =calcmove - 360; }} if (abs(calcmove)>=StearingMinToMove) { if (abs(calcmove)>=StearingMaxMove) { if (calcmove <0) { cm =(StearingMaxMove * -1); Kalkbewegung =cm; aufrechtzuerhalten. Sonst {cm =(StearingMaxMove * 1); Kalkbewegung =cm; } } Stearing =(calcmove * StearingCoeffMove); gomotor (int ((Stearing * 216) / 360)); // 54 Schritte =1/4 der Umdrehung prevStearing =Stearing; isStearing =wahr; aufrechtzuerhalten. gomotor (int ((Stearing * 216) / 360)); // 54 Schritte =1/4 der Umdrehung Stearing =0; prevStearing =0; isStearing =false; } } previousStearingMillis =currentStearingMillis; } // RC-RF-TASTEN ------------------ rfRemoteControlValue =checkRfRC (); if (rfRemoteControlValue) { switch (rfRemoteControlValue) { case RCleftbutton:// Linke RC-Taste goleft(); brechen; case RCrightbutton:// Rechte RC-Taste goright(); brechen; case RCleft10button:// Left-10 RC-Taste goleft10(); brechen; case RCright10button:// Rechts+10 RC-Taste goright10(); brechen; } } // BUTTONS ---------------------- HWButtonValue =checkHWButtons(); if (HWButtonValue) { switch (HWButtonValue) { case HWleftbutton:// Left (-1) HW button if (isSetup ==false) { goleft (); aufrechtzuerhalten. Sonst { setupMinus(); } brechen; case HWrightbutton:// Right(+1) HW button if (isSetup ==false) { goright(); aufrechtzuerhalten. Sonst { setupPlus(); } brechen; case HWpausebutton:// Pause HW button gopause(); brechen; case HWsetupbutton:// Setup HW Button gosetup(); brechen; case HWleft10button:// Left(-10) HW button goleft10(); brechen; Fall HWright10button:// Rechts (+10) HW-Taste goright10(); brechen; aufrechtzuerhalten. ret =nmeaExtractData(); Eingabezeichenfolge =""; stringComplete =false; if (ret ==true) { RefreshDisplay(); }} // WATCHDOG FEEDING ---------------- if (digitalRead (watchDogPin) ==LOW) { digitalWrite (watchDogPin, HIGH); aufrechtzuerhalten. Sonst { DigitalWrite (watchDogPin, LOW); }} // Sensoren auf Multiplexervoid lesen readMuxSensors () { float Vo =0; Schwimmer n =0; Schwimmer n1 =0; Float v1ad =0; Float v2ad =0; Schwimmerkorr =0; Schwimmer R1 =10000; Schwimmer logR2 =0; Schwimmer R2 =0; Schwimmer T =0; Schwimmer c1 =1,009249522e-03; Gleitkomma c2 =2,378405444e-04; Gleitkomma c3 =2.019202697e-07; digitalWrite (MuxSelBit0Pin, LOW); // 00=Vbatt digitalWrite (MuxSelBit1Pin, LOW); n =analogRead (MuxIOPin); v1ad=n; n1=((((10,00 * n) / 1023.00)); SensorVBatt=(n1 + ((n1 * 0,0) /100)); // willkürliche Korrektur (nicht aktiv =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)); // willkürliche Korrektur (nicht aktiv =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)); Sensortemperatur =T - 273,15; // Celsius n =(v1ad - v2ad); n1 =(n / 0,22) * 1000,00; SensormAmp =((((10.00 * n1) / 1023.00));} // Daten aus nmea extrahieren inputStringbool nmeaExtractData() { bool ret =false; //true if nmea Satz =$GNRMC und gültiges CHKSUM if ((inputString.substring(0,6) =="$GNRMC") &&(inputString.substring(inputString.length()-4,inputString.length()- 2) ==nmea0183_checksum(inputString))) { y=0; for (s =1; s <11; s ++) { y=inputString.indexOf(",",y); Schalter (s) { Fall 1://Zeit 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; brechen; Fall 2://Gültigkeit z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_validity=inputString.substring(y+1,y+1+1); } y=z; brechen; Fall 3://Breitengrad 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; brechen; Fall 4://Nord/Süd z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_latitude=nm_latitude + inputString.substring(y+1,y+1+1); } y=z; brechen; Fall 5://Längengrad 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; brechen; Fall 6://Ost/West z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_longitude =nm_longitude + inputString.substring(y+1,y+1+1); } y=z; brechen; Fall 7:// Geschwindigkeitsknoten z=inputString.indexOf(",",y+1); if (z>(y+1)) { nmf_knots=inputString.substring(y+1,z).toFloat(); t=roundOneDec(nmf_knots); nm_knots=String(t,1)+"kn"; } y=z; brechen; Fall 8://wahrer Kurs 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; brechen; Fall 9://Datum 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; brechen; Fall 10:// Anweisungen break; default:// Anweisungen break; }} if ((isfirstfix ==true) || (ispause ==true)) { nm_routetofollow=nm_truecourse; nmf_routetofollow=nmf_truecourse; isfirstfix=false; } ret=wahr; } return ret;} // Parameterwert erhöhen (+) während des Setupvoid setupPlus () { Schalter (SetupParameter) { Fall 2:// Intervall StearingInterval =(StearingInterval + 100); if (StearingInterval> 5000) { StearingInterval =5000; } brechen; Fall 3://min. zu bewegen StearingMinToMove =(StearingMinToMove + 1); if (StearingMinToMove> 20) { StearingMinToMove =20; } brechen; Fall 4://max. bewegen StearingMaxMove =(StearingMaxMove + 1); if (StearingMaxMove> 45) { StearingMaxMove =45; } brechen; Fall 5://Koeffizient StearingCoeffMove =(StearingCoeffMove + 0.1); if (StearingCoeffMove> 4) { StearingCoeffMove =4; } brechen; } Verzögerung (200); RefreshDisplay();} // Parameterwert verringern (-) während des Setupvoid setupMinus() { switch (SetupParameter) { Fall 2://Intervall StearingInterval =(StearingInterval - 100); if (StearingInterval <1000) { StearingInterval =1000; } brechen; Fall 3://min. zu bewegen StearingMinToMove =(StearingMinToMove - 1); if (StearingMinToMove <0) { StearingMinToMove =0; } brechen; Fall 4://max. move StearingMaxMove =(StearingMaxMove - 1); if (StearingMaxMove <10) { StearingMaxMove =10; } brechen; Fall 5://Koeffizient StearingCoeffMove =(StearingCoeffMove - 0.1); if (StearingCoeffMove <0,1) { StearingCoeffMove =0,1; } brechen; } Verzögerung (200); RefreshDisplay();} // Motorsteuerung (+) =vorwärts (-) =rückwärtsvoid gomotor (int stepsToMove) { digitalWrite (motorsABenablePin, HIGH); motor.step (stepsToMove); digitalWrite(motorsABenablePin, LOW);}// refresh data on displayvoid RefreshDisplay() { if (isSetup ==false) { //---------normal lcd.clear(); lcd.setCursor(0,0); lcd.print("R"+nm_routetofollow); lcd.write(0xDF); lcd.print(" H"+nm_truecourse); lcd.write(0xDF); if (ispause ==true) { lcd.print(" STOP"); } 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"); break; case 2://interval lcd.print("interval"); lcd.setCursor(7,1); lcd.print(StearingInterval); lcd.print(" mSec"); break; case 3://min. to move lcd.print("minimum"); lcd.setCursor(7,1); lcd.print(StearingMinToMove); lcd.write(0xDF); break; case 4://max. move lcd.print("max"); lcd.setCursor(7,1); lcd.print(StearingMaxMove); lcd.write(0xDF); break; case 5://coefficient lcd.print("coeffic."); lcd.setCursor(7,1); lcd.print(StearingCoeffMove); lcd.print(" x "); lcd.write(0xDF); break; } }}/* 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 ich; // 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... "); Verzögerung (1000); goupdateEEPROM(); if (EEerr) { lcd.print("E="); lcd.print(EEerr); Verzögerung (1000); } prev_StearingInterval =StearingInterval; prev_StearingMinToMove =StearingMinToMove; prev_StearingMaxMove =StearingMaxMove; prev_StearingCoeffMove =StearingCoeffMove; } isSetup =false; } } NewTone (speakerPin,2000); Verzögerung (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); Verzögerung (200); noNewTone(); } else { NewTone (speakerPin,1000); Verzögerung (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); Verzögerung (200); noNewTone(); } else { NewTone (speakerPin,1000); Verzögerung (50); noNewTone(); } RefreshDisplay();}void gopause() { // pause button/RC if (ispause ==true) { ispause=false; digitalWrite(ledpausePin, HIGH); NewTone (speakerPin,50); Verzögerung (200); NewTone (speakerPin,200); delay(800); noNewTone(); } else { ispause=true; digitalWrite(ledpausePin, LOW); NewTone (speakerPin,200); Verzögerung (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); Verzögerung(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); Verzögerung (500); digitalWrite(restartPin, LOW); //restart CLIENT tone(buzzerPin,1500); Verzögerung (500); digitalWrite(restartPin, HIGH); tone(buzzerPin,1500); delay(timeForClientStart); // let CLIENT time to restart... noTone(buzzerPin); currentMillis =millis(); previousFeedingState =LOW; previousFeedingMillis =currentMillis; previousLedMillis =currentMillis; }}

Kundenspezifische Teile und Gehäuse

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

Schaltpläne


Herstellungsprozess

  1. DIY Infrarot-Bewegungssensorsystem für Raspberry Pi
  2. Bauen Sie ein ballistisches Fallschirm-Wiederherstellungssystem für Ihre Drohne
  3. Ist ein kontinuierliches Überwachungssystem das Richtige für Sie?
  4. Automatischer Werkzeugwechsler für Roboter
  5. Ist Ihr System bereit für IoT?
  6. Polygonfräser für Drehautomaten
  7. CNC-Drehautomat für Präzisionsteile
  8. Antriebssystem für Überschallflüge
  9. Arbeitsprinzip des manuellen und automatischen Getriebesystems
  10. Automatikgetriebe verstehen