mein LDR Projekt hab ich erstmal auf Eis gelegt, da ich mir schon dachte, für Kinder eher uninteressant. Hab mich dann doch eher für einen HC-SR04 entschieden. Das läuft auch alles stabil, ABER ich hätte gerne das die Funktion taschenlampe() solange wiederholt wird, bis ein anderer Tastendruck z.B. F die Funktion abbricht und er zu Bluetooth zurückkehrt. Ich hab schon mit while und for rum experimentiert, aber kam immer nicht mehr aus der Schleife raus
/**
Author: Omar Draidrya
Date: 2024/07/03
This code controls the forward and backward movement of a motor using an H-bridge.
*/
#include <AFMotor.h>
#include <Arduino.h>
byte triggerPin = A4;
byte echoPin = A5;
int duration, distance;
int number = 0;
byte star = 1;
AF_DCMotor motor1(1); // Create motor #1 using M1 connector
AF_DCMotor motor2(2); // Create motor #2 using M2 connector
AF_DCMotor motor3(3); // Create motor #3 using M3 connector
AF_DCMotor motor4(4); // Create motor #4 using M4 connector
char command;
void setup() {
Serial.begin(9600); // Start serial communication at 9600 baud rate
motor1.setSpeed(150); // Set initial motor speeds
motor2.setSpeed(150);
motor3.setSpeed(150);
motor4.setSpeed(150);
pinMode(triggerPin, OUTPUT);
pinMode(echoPin, INPUT);
}
void loop() {
connection();
taschenlampe_data();
}
void connection() {
if (Serial.available() > 0) {
command = Serial.read();
Serial.println(command); // Read the incoming command
switch (command) {
case 'F':
forward();
break;
case 'B':
backward();
break;
case 'L':
turnLeft();
break;
case 'R':
turnRight();
break;
case 'S':
stop();
break;
case 'X':
taschenlampe();
break;
}
}
}
void taschenlampe_data() {
distance = 0;
digitalWrite(triggerPin, LOW);
delayMicroseconds(4);
digitalWrite(triggerPin, HIGH);
delayMicroseconds(10);
digitalWrite(triggerPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = round(duration * .0343) / 2;
Serial.print("Distance: ");
Serial.println(distance);
delay(100);
}
void taschenlampe() {
switch (distance) {
case 1 ... 15:
backward();
//Serial.println("vorwärts");
delay(1200);
drive();
//Serial.println(number);
break;
case 16 ... 30:
motor1.setSpeed(90);
motor2.setSpeed(90);
motor3.setSpeed(90);
motor4.setSpeed(90);
forward();
//Serial.println("langsam vor");
break;
case 31 ... 300:
forward();
//Serial.println("Vorwaerts");
break;
default:
backward();
//Serial.println("default");
break;
}}
void drive() {
number = random(3);
if (number == 1) {
turnLeft();
delay(1500);
} else {
turnRight();
delay(1500);
}
}
void forward() {
motor1.run(FORWARD);
motor2.run(FORWARD);
motor3.run(FORWARD);
motor4.run(FORWARD);
}
void backward() {
motor1.run(BACKWARD);
motor2.run(BACKWARD);
motor3.run(BACKWARD);
motor4.run(BACKWARD);
}
void turnLeft() {
motor1.run(BACKWARD);
motor2.run(BACKWARD);
motor3.run(FORWARD);
motor4.run(FORWARD);
}
void turnRight() {
motor1.run(FORWARD);
motor2.run(FORWARD);
motor3.run(BACKWARD);
motor4.run(BACKWARD);
}
void stop() {
motor1.run(RELEASE);
motor2.run(RELEASE);
motor3.run(RELEASE);
motor4.run(RELEASE);
}
dein connection() reagiert nur auf neu hereinkommende Befehle.
ein Befehl löst eine Funktion somit einmal aus.
EINMAL.
Was du machen könntest, dass du dir auch merkst was der letzte Befehl war.
Dann kannst du z.B. im loop auch prüfen, ob der letzte Befehl 'X' war und die taschenlampe() ausführen.
Sauberer ist, du zeichnest dir eine klare finite state machine, führst bestimmte befehle bei einem Statusübergang aus (stop(), forward(), ...) bzw. machst auch aktivitäten dauerhaft (z.b. taschenlampe())
steuerst du Motoren an. Du brauchst zuerst einmal einen Plan, was wann geschehen soll. Diesen Plan setzt du dann in einer finite state machine um. In jeden State gibt es eine oder mehrere Bedingungen, wie der Status verlassen werden kann und was dann die Aktion ist und was der neue Status ist. Ohne eine Statemaschine wirst du dein Auto nie richtig zum laufen bekommen.
Und noch was: Vergiss das es delay gibt. Wartezeiten werden auch in der Statemaschine gemacht. Bei dem Auto ist ein delay fahren ohne die Hände am Lenkrad zu haben und mit geschlossenen Augen. Die nächste Wand kommt bestimmt.
while und for brauchst du nicht. Du hast eine Schleife und die heißt loop.
Einfach in der While-Schleife die Taste abfragen und dann die Bedingung der Schleife ändern. Meist bedeutet das, den Pin_Status abzufragen, an den die Taste angeklemmt ist. Man muss sich nur mit sich selbst einigen, ob Low oder High der "unbenutzte" Zustand ist, und abfragen ob der Zustand ein anderer ist.
Das schlimmste was es gibt, dafür ist die loop da, und nicht blockieren ganze loop.
Dazu nicht gelesen ! es wird kein Taster benutzt.
Und komm nicht mit blöden Kommentaren!.
Das einzige was mich jetzt noch wirklich nervt, ist der Servo. Der geht zu langsam. Könnte man den Code so umbauen, dass er bei 135°, 90° und 45° scannt?
Alles ganz entspannt ich bin ja froh das du dir überhaupt die Zeit nimmst mir zu helfen Also warte ich solange es eben dauert und währenddessen kann ich ja selber rum probieren
Alles ganz entspannt ich bin ja froh das du dir überhaupt die Zeit nimmst mir zu helfen Also warte ich solange es eben dauert und währenddessen kann ich ja selber rum probieren
Las Dir mal die Zeiten ausgeben, wann die Servoroutine aufgerufen wird:
void setServoGetDist()
{
uint32_t myMillis = millis();
if (myMillis - lastServoAction > 15) // Pause für Echounterdrückung
{
if (lastServoAction != 0)
{
Serial.print(F("timing: "));
Serial.println(myMillis - lastServoAction);
}
lastServoAction = myMillis;
constexpr uint8_t fieldTicks{ (maxPoint - minPoint) / 3 }; // (40) gleichmässig Bereiche über den gesamten Arbeitsbereich verteilen
static uint32_t tempData = 0;
uint16_t d = ultra();
tempData += d;
/*
Serial.print(F("Dura: "));
Serial.print(d);
Serial.print(F(" Summe: "));
Serial.println(tempData);
*/
switch (pos)
{
case minPoint: // (30) ganz links
if (!richtung) // kommt von rechts
{
cml = tempData / (fieldTicks - 1);
}
Serial.println(F("Servo links"));
richtung = HIGH; // Richtungsumkehr
tempData = 0;
break;
case minPoint + fieldTicks: // (30+40 = 70)Ende linke Ausleuchtung - Anfang Mitte
if (richtung) // Auf dem Weg nach rechts
{
cml = tempData / (fieldTicks - 1);
}
else // auf dem Weg nach links
{
cm = tempData / (fieldTicks - 1);
}
Serial.println(F("tick 70"));
tempData = 0;
break;
case maxPoint - fieldTicks: // (150-40 = 110) Ende Mitte - Anfang rechte Ausleuchtung
if (!richtung) // Auf dem Weg nach links
{
cmr = tempData / (fieldTicks - 1);
}
else // Auf dem Weg nach rechts
{
cm = tempData / (fieldTicks - 1);
}
Serial.println(F("110 tick"));
tempData = 0;
break;
case maxPoint: // (150) ganz rechts
if (richtung)
{
cmr = tempData / (fieldTicks - 1);
}
Serial.println(F("Servo rechts"));
richtung = LOW;
tempData = 0;
break;
}
if (richtung)
{
pos++;
}
else
{
pos--;
}
// Fehlerbehandlung
if (pos > maxPoint)
{
pos = maxPoint;
Serial.println(F("maxPosFail"));
}
if (pos < minPoint)
{
pos = minPoint;
Serial.println(F("minPosFail"));
}
myservo.write(pos); // Servo setzen
}
}
Das sollte ungefähr an den 15 ms (+ maximal 2) dran sein.
Wenn nicht kommentiere im loop() einfach mal automatic() aus. Wenn es dann passt, liegt da irgendwo der Hund begraben.
Normalerweise müsstest Du in
135-45 = 90 ticks mit je 15ms einmal rum sein: 90*15 = 1350.
Wenn das so passt und zu langsam ist, kannst Du pos++ / pos-- ersetzen durch
Das ist 40mal soviel, wie Du vorgesehen hast ....
Also action() und ultra() auskommentieren und sehen, ob sich was ändert.
Dann erst ultra() wieder rein und wen die Zeiten dann noch passen muss action() untersucht werden, wo es klemmt.
Ok, dann mach das mit den Postionsänderungen wie in 17 angedacht.