Hallo,
erstmal vorab zu meiner “IST-Situation”. Wir arbeiten an der Arbeit mit 8 Auszubildenden (Zerspaner, Werkzeugmechaniker, Industrimechaniker, Mechatroniker, Elektroniker (zu denen ich auch gehöre)) daran, ein BobbyCar so umzubauen, dass es fernsteuerbar ist mit einer 4-CH RC Fernbedienung (Modelcraft GT4; zu finden bei Conrad). Als Antrieb dient ein Boschakkuschrauber, bei welchem der “Gashebel”, sowie Links-/Rechtslauf mit Servos betätigt werden sollen. Ebenso gibt es einen “großen” Servo für die Lenkung. Die Königsdisziplin für das BobbyCar wird am Ende der “Follow the Line” Wettkampf, bei dem das BobbyCar autark einer 18mm breiten schwarzen Linie folgen soll (Schwarzes Iso-Tape).
Bisher habe ich folgendes erreichen können:
über 2 LDR und eine weiße LED als Referenzlichtquelle ist der Arduino in der Lage über die Analogeingänge Differenzen zwischen “hell” & “dunkel” zu erkennen und den Lenkungsservo entsprechend nachzuregeln.
Was mir im Moment Kopfschmerzen bereitet, ist, dass ich das PWM Signal der Fernbedienung gerne durch den Arduino durschleifen möchte, da es so ist, dass wenn ich es mit pulseIn auswerten möchte, die Servos ohne Ende anfangen zu zittern und zu knurren, wenn ich die Pulslänge über “writeMicroseconds” wieder auf die Ausgänge schreibe, an welchen der Steuereingang des jeweiligen Servos hängt. Ich vermute, dass es mit der “Toleranz” / “Auflösung” von pulseIn zusammen hängt (4µs Toleranz / 5,5 µs Pulslängenänderung = 1° Verstellung des Servos).
Ich habe zuvor versucht das ganze in Anführungszeichen mathematisch zu lösen: arithmetischer Mittelwert aus 3 Signalen und das ganze dann durch Multiplikation und Division zu “glätten” (bei 10 als Faktor bspw. abschneiden der letzten Zahl), allerdings fährt der Servo dadurch extrem ruckelig (was ja auch klar ist, da er ja keine vollen 180° mehr als Befehlssatz hat, sondern entsprechend weniger und dadurch springt).
Ich habe mir schon mit meinem Elektronikerkollegen die Finger wund gegoogelt aber wir finden einfach keinen Lösungsansatz…
Ich hoffe ihr könnt mir helfen, dass der Arduino entweder im Stande ist, dass PWM Signal wirklich genau genug auszuwerten und diese Varianz in den Werten weg zu bekommen (“jitter” der Servos) oder aber (auch wenn es schade ist um die bisherige Arbeit am Script), das Signal einfach “durchzuschleifen” also das Signal 1 zu 1 im “Handbetrieb” von Eingang zu Ausgang zu schieben, so lange, wie es nun mal ansteht.
Vielen Dank im Voraus!
Liebe Grüße
neongruuen + Kollegen
#include <Servo.h> //Servo Library importieren um Servosignal zu generieren
Servo lenkung; //Servo "Lenkung" definieren
Servo antrieb; //Servo "Antrieb" definieren
Servo fahrtrichtung; //Servo "Fahrtrichtung" definieren
/*
Im Folgenden werden die Variablen deklariert; prinzipiell selbsterklärend;
avg => average Summenelemente zur Mittelwertsbildung
pulseDELAY => TIMEOUT für pulseIn funktion -> nach Wert ohne Pulse -> kein Puls vorhanden
glCH1 => Glättungsfaktor Channel 1
glCH2 => Glättungsfaktor Channel 2
*/
int CH1in = 2;
int CH1;
int CH1puff = 0;
int CH2in = 3;
int CH2;
int CH2puff = 0;
int CH3in = 4;
int CH3;
int CH4in = 5;
int CH4;
int avg = 3;
int pulseDELAY = 21000;
int glCH1 = 15;
int glCH2 = 15;
boolean runAUTO = false;
boolean calib = false;
int calibNUM = 3;
int calibLDR1 = 0;
int calibLDR2 = 0;
int calibPUFF1 = 0;
int calibPUFF2 = 0;
int calibOffset = 50;
int lenkMid = 90;
int lenkOffset = 45;
int LDR1 = 0;
int LDR2 = 0;
void setup(){
// Setup & Pre-Load
// Kanäle als Input deklarieren; Serielle Schnittstelle starten ( Debugging ); Variablen zu Servo Kanälen (I/O) zuordnen
pinMode (CH1in,INPUT);
pinMode (CH2in,INPUT);
pinMode (CH3in,INPUT);
pinMode (CH4in,INPUT);
lenkung.attach(6);
antrieb.attach(7);
fahrtrichtung.attach(8);
//Debugging
//Serial.begin(9600);
//Serial.println(F("PWM-Signalwerte werden eingelesen"));
}
void loop() {
// Maincode
CH4 = pulseIn(CH4in, HIGH, 21000);
if (1800 < CH4 && CH4 < 2100){ //bei jedem Drücken des Tasters für CH4 wird die Variable "runAUTO" getoggelt (1 & 0 hin und her geschaltet)
runAUTO = !runAUTO;
delay(1000);
}
if (runAUTO == 0){
CH1puff=0; //Puffervariable für Signallaufzeit am Anfag eines Loops auf 0 setzten
CH2puff=0; //Puffervariable für Signallaufzeit am Anfag eines Loops auf 0 setzten
for (int i = 0; i < avg; i++){ //Mittelwertsbildung mit Summenwerten
CH1 = pulseIn(CH1in, HIGH, pulseDELAY);
CH1puff = CH1puff + CH1;
}
CH1 = CH1puff / avg;
if (CH1 < 1010){ //Werte entstören
CH1 = 1000;
}
if (1490 < CH1 && CH1 < 1510){
CH1 = 1500;
}
if (CH1 > 1975){
CH1 = 2000;
}
CH1 = CH1 / glCH1; //Werte glätten
CH1 = CH1 * glCH1;
for (int i = 0; i < avg; i++){ //Mittelwertsbildung mit Summenwerten
CH2 = pulseIn(CH2in, HIGH, pulseDELAY);
CH2puff = CH2puff + CH2;
}
CH2 = CH2puff / avg;
if (CH2 < 1005){ //Werte entstören
CH2 = 1000;
}
if (1490 < CH2 && CH2 < 1510){
CH2 = 1500;
}
if (CH2 > 1975){
CH2 = 2000;
}
CH2 = CH2 / glCH2; //Werte glätten (15er Schritte)
CH2 = CH2 * glCH2;
CH3 = pulseIn(CH3in, HIGH, 21000);
if (CH3 < 1300){
fahrtrichtung.write(45);
}
if (CH3 > 1600){
fahrtrichtung.write(135);
}
// Ausgänge beschalten
lenkung.writeMicroseconds(CH1); //Entstörten und geglätteten Impuls an Servo senden
antrieb.writeMicroseconds(CH2); //Entstörten und geglätteten Impuls an Servo senden
}
/* ab hier automatisches Fahren!!! */
// KALIBRIERUNG!! TO DO!!
if (calib == 0 && runAUTO == 1){ //Wenn noch nicht Kalibriert, aber Automatik an
int e = 0; // FOR Schleifen Variable extern defniert, zur weiteren verwendung, s.u.
for (e; e < calibNUM; e++){ //Mittelwertsbildung mit Summenwerten
calibLDR1 = analogRead(A0); //Analogeingang einlesen
calibPUFF1 = calibPUFF1 + calibLDR1; //Summe aus "calibNUM"-Durchläufen bilden
delay(10); //10 ms abwarten
calibLDR2 = analogRead(A1); //Analogeingang einlesen
calibPUFF2 = calibPUFF2 + calibLDR2; //Summe aus "calibNUM"-Durchläufen bilden
delay(10); //10 ms abwarten
}
if (e == calibNUM){ //Wenn alle Durchläufe abgearbeitet
calib = 1; //FLAG für Kalibrierung auf TRUE setzen
calibLDR1 = calibPUFF1 / calibNUM; //Mittelwert bilden
calibLDR2 = calibPUFF2 / calibNUM; //Mittelwert bilden
}
}
if (calib == 1 && runAUTO == 0){ //Wenn Kalibriert, aber Automatik aus = Kalibrierung löschen (ermöglicht Fahren auf verschiedenen Untergründen
calib = 0;
calibPUFF1 = 0; //Kalibrierungspuffer löschen
calibPUFF2 = 0; //Kalibrierungspuffer löschen
}
// KALIBRIERUNG ENDE!!
if (runAUTO == 1 && calib == 1){ //Wenn Kalibriert & Automatik ein
LDR1 = analogRead(A0); //Sensorik einlesen
LDR2 = analogRead(A1); //Sensorik einlesen
//Antrieb einfügen, wenn Mechanik steht!
//Antrieb ENDE!
if (LDR1 - calibLDR1 > calibOffset){ //Wenn Differenz zwischen kalibriertem Wert und Aktualwert größer Offset
lenkung.write(lenkMid + lenkOffset); //Lenkung nachregeln
}
else if (LDR2 - calibLDR2 > calibOffset){ //Wenn Differenz zwischen kalibriertem Wert und Aktualwert größer Offset
lenkung.write(lenkMid - lenkOffset); //Lenkung nachregeln
}
else {
lenkung.write(lenkMid); //Wenn Differenz kleiner als Offset = Lenkung Mittelstellung
}
}
// DEBUGGING START!
// Serial.println(runAUTO);
//Serial.println("CH1"); //Werte auf serieller Schnittstelle ausgeben
//Serial.println(CH1);
//Serial.println("CH2"); //Werte auf serieller Schnittstelle ausgeben
//Serial.println(CH2);
//Serial.println("CH3"); //Werte auf serieller Schnittstelle ausgeben
//Serial.println(CH3);
//Serial.println("CH4"); //Werte auf serieller Schnittstelle ausgeben
//Serial.println(CH4);
//delay(1000);
// DEBUGGING ENDE!
}