Die zusammengebaute Struktur sieht so aus
Komponenten
Die Basis ist ein mobiles zweiteiliges Robo-Plattform- Auto-Chassis 2WD Mini Kit
Plattformabmessungen: 135 mm x 135 mm x 80 mm Der
Antrieb besteht aus zwei Standardmotorrädern mit einem Getriebe und einem Gleichstrommotor mit Rasterscheiben für Geschwindigkeitssensoren:
- Nennstrom: 250mA max. bei einer Spannung von 3,6 V.
- Drehmoment 800 g / cm (bei 6V Spannung)
- Versorgungsspannung: 6 - 8 V.
- Leerlaufdrehzahl: 170 U / min (bei 3,6 V)
- Übersetzungsverhältnis: 1: 48
- Achsen kommen auf beiden Seiten heraus
- Achsdurchmesser: 5 mm
- Abmessungen: 64x20x20 mm
- Gewicht: 26g
Das MX1508 Modul wurde ausgewählt , als der Motor driver.You
können lesen über das Modul hier
Technische Daten:
- Versorgungsspannung: 2 - 10 V.
- Arbeitstreiber pro Kanal: 1,5 A (Spitzenstrom 2,5 A, nicht mehr als 10 Sekunden)
- Logikeingang: 5V
- Abmessungen: 24,7 x 21 x 0,5 mm
Für die horizontale und vertikale Bewegung der IP-Kamera wurden die beliebten SG90 2-kg- Servomotoren ausgewählt. Die folgende Spezifikation wird auf der Website des Herstellers vorgestellt:
- Gewicht: 9g
- Abmessung: 23 × 12,2 x 29 mm
- Blockierdrehmoment: 1,8 kg / cm (4,8 V)
- Getriebetyp: POM-Zahnradsatz
- Betriebsgeschwindigkeit: 0,1 Sekunden / 60 Grad (4,8 V)
- Betriebsspannung: 4,8V
- Temperaturbereich: 0 ℃ _ 55 ℃
- Totbandbreite: 1us
- Stromversorgung: Durch externen Adapter
- Servodrahtlänge: 25 cm
- Servostecker: JR (passend für JR und Futaba)
Für die Webcam wurde ein FPV-
Halterungskit ausgewählt. Beschreibung des Halters im Online-Shop: „Mit FPV können Sie Ihre FPV-Kamera in drei Ebenen ausrichten. Durch die einfache Verbindung und Bedienung können Sie die Plattform schnell zusammenbauen und mit dem Controller oder Flugcontroller verbinden. Wird in Verbindung mit EMAX 9g ES08A Mini Servo oder SG90 Servos (mit einigen Modifikationen) verwendet. "
"Mit einigen Änderungen" - sollte berücksichtigt werden, musste die Menge mit einer Datei im wörtlichen Sinne geändert werden. Aber für einen Heimwerker für 3 Dollar ist das so ziemlich nichts. Einige beschwerten sich, dass selbst die Überarbeitung nicht half und die Servos nicht in die Größe passten, in meinem Fall alle Regeln. Mit zwei SG90-Dias wird die Kamera horizontal und vertikal bewegt. Die Option zum Entwerfen und Drucken auf einem 3D-Drucker wurde ebenfalls in Betracht gezogen, aber bisher blieb ich bei diesem Halter stehen.
IP-Kamera basierend auf ESP32-CAM
Wie beschrieben: „ Das I2S-Subsystem im ESP32 bietet auch einen Hochgeschwindigkeitsbus, der für den direkten Speicherzugriff direkt mit dem RAM verbunden ist. Einfach ausgedrückt können Sie das ESP32 I2S-Subsystem so konfigurieren, dass parallele Daten unter Hardwaresteuerung gesendet oder empfangen werden. “
Jene. Sie können die I2S ESP32-Schnittstelle so konfigurieren, dass parallele Daten unter Hardwaresteuerung gesendet oder empfangen werden, die für den Anschluss der Kamera implementiert ist. Dieses Board wurde von Seeed Studio entwickelt, der Preis beträgt hier 9,90 USD, aber in unseren Radiogeschäften werden sie für 8 USD verkauft, anscheinend kann nicht nur Seeed Studio sie produzieren.
Technische Daten:
- Das kleinste 802.11b / g / n Wi-Fi BT SoC-Modul
- 32-Bit-CPU mit geringem Stromverbrauch, kann auch den Anwendungsprozessor bedienen
- Bis zu 160 MHz Taktrate , Zusammenfassung Rechenleistung bis zu 600 DMIPS
- Eingebauter 520 KB SRAM, externer 4MPSRAM
- Unterstützt UART / SPI / I2C / PWM / ADC / DAC
- Unterstützt OV2640- und OV7670-Kameras, eingebaute Blitzlampe.
- Support Image WiFI Upload
- Unterstützt TF-Karte
- Unterstützt mehrere Schlafmodi.
- Embedded Lwip und FreeRTOS
- Unterstützt den Betriebsmodus STA / AP / STA + AP
- Unterstützt die Smart Config / AirKiss-Technologie
- Unterstützung für lokale und Remote-Firmware-Upgrades der seriellen Schnittstelle (FOTA)
Energiequelle
Die Plattform wurde lange Zeit nicht ohne Aufladen von der autonomen Stromversorgung gesteuert. Daher wurde ein 2A 18650-Netzteilmodul mit einem USB-Ausgang mit einem Steckplatz als Quelle ausgewählt.
Spezifikationen:
- Batterietyp: 18650 Li-Ion (kein Schutz)
- Ladespannung: 5V bis 8V
- Ausgangsspannungen:
- 3V - direkt von der Batterie durch die Schutzeinrichtung
- 5V - durch einen Aufwärtswandler.
- Maximaler Ausgangsstrom:
- Ausgang 3V - 1A
- Ausgang 5V - 2A
- Maximaler Ladestrom: 1A
- Eingangsanschlusstyp: Micro-USB
- Ausgangsanschlusstyp: USB-A
- 5V Verbraucher - durch Überlastung und Kurzschluss
- Maße:
- Leiterplatte: 29,5 x 99,5 x 19 mm
- Ganzes Gerät: 30 x 116 x 20 mm
ESP-WROOM-32 wurde als Hauptcontroller ausgewählt.
Zuvor habe ich die Eigenschaften des ESP32 ausführlicher beschrieben. Hier sind die grundlegenden Eigenschaften des Moduls:
- Xtensa LX6 32-Bit-Dual-Core-Mikroprozessor bis 240 MHz
- Flash-Speicher: 4 MB
- Drahtlose Kommunikation Wi-Fi 802.11b / g / n bis zu 150 Mb / s, Bluetooth 4.2 BR / EDR / BLE
- Unterstützt STA / AP / STA + AP-Modi, integrierten TCP / IP-Stack
- GPIO 32 (UART-, SPI-, I2C-, I2S-Schnittstellen, PWM, SD-Controller, kapazitive Berührung, ADC, DAC und mehr
- Stromversorgung: über Micro-USB-Anschluss (CP2102-Wandler) oder Ausgänge
- Pin-Abstand: 2,54 mm (kann in Steckbrett eingesetzt werden)
- Brettgröße: 5,2 x 2,8 cm
Zwei optische Encoder "Noname" werden als Geschwindigkeitssensoren zum Zählen der Drehimpulse der Rasterscheiben des Motorrades verwendet.
Eigenschaften:
- Versorgungsspannung: 3,3V - 5V
- Sensornutbreite: 6 mm;
- Ausgabetyp: analog und digital
- Anzeige: Ausgangsstatus
Der beliebte Ultraschall-Entfernungsmesser HC-SR04 wurde zur Entfernungsmessung verwendet.
Merkmale:
- Versorgungsspannung: 5V
- Verbrauch im lautlosen Modus: 2mA
- Verbrauch während des Betriebs: 15 mA
- Entfernungsbereich: 2-400 cm
- Effektiver Betrachtungswinkel: 15
- Arbeitsblickwinkel: 30 °
Software-Implementierungen
Der erste Schritt war das Kennenlernen und Flashen des ESP32-CAM-Moduls.
Die Beschreibung der Arbeit mit dem Modul wird auf Harba hier, hier und auf anderen Ressourcen präsentiert.
Die meisten Artikel beschreiben einen einfachen Flash- Vorgang mit der Arduino IDE. In den meisten Fällen reicht dies aus, und am Anfang war diese Option auch in Ordnung.
In Radiogeschäften werden ESP32-CAM-Module mit einer OV2640-Kamera verkauft, daher muss eine kleine Änderung in der Skizze vorgenommen werden:
// Select camera model
//#define CAMERA_MODEL_WROVER_KIT
//#define CAMERA_MODEL_ESP_EYE
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE
#define CAMERA_MODEL_AI_THINKER
Geben Sie außerdem die SSID und das Kennwort für den Wi-Fi-Zugangspunkt an
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Eine der Bedingungen, unter denen eine Webkamera in meinem Fall funktioniert, ist die Fähigkeit, einen Videostream über den Keenetic-Proxyserver zu übertragen. Ich verwende einen Keenetik Viva-Heimrouter. Der KeenDNS-Dienst stellt den Domänennamen für die Home-Webressource bereit. Zu meiner Überraschung schlug der erste Versuch jedoch fehl. Beim Versuch, über das Internet remote zuzugreifen, wurde die Fehlermeldung "Header-Felder sind zu lang, als dass der Server sie interpretieren könnte" angezeigt. Mit diesem Problem bin ich zum ersten Mal konfrontiert. Die Lösung für dieses Problem besteht beispielsweise darin, die Konfiguration CONFIG_HTTPD_MAX_REQ_HDR_LEN zu ändern
#define CONFIG_HTTPD_MAX_REQ_HDR_LEN 2048
Bei der Arduino IDE ESP32 sind die Module bereits kompiliert und als statische Bibliotheken dargestellt, die sich in Windows unter dem Pfad% userprofile% \ AppData \ Local \ Arduino15 \ packages \ esp32 \ hardware \ esp32 \ 1.0.4 \ tools \ sdk \
Just befinden Das Ändern des Parameters in der Kopfzeile führt zu nichts.
Das heißt, um die Konfiguration zu ändern, müssen wir die ESP-IDF-Bibliotheken neu kompilieren.
Die Lösung bestand darin, das Projekt github.com/espressif/esp-who zu klonen . In dem Verzeichnis mit Beispielen finden wir das Projekt camera_web_server, ändern den Parameter der maximalen Header-Länge und vergessen nicht, die Einstellungen
für die Wi-Fi-Verbindung anzugeben. Damit das Projekt kompiliert werden konnte, mussten wir ein weiteres Kontrollkästchen installieren - Support-Array 'rtc_gpio_desc' für ESP32
Gehen Sie nach erfolgreicher Kompilierung und dem Laden des Projekts zur entsprechenden IP-Adresse im Browser und rufen Sie die Seite mit der Oberfläche unserer Webkamera auf.
Die Benutzeroberfläche ähnelt den Arduino-Beispielen, es wurden jedoch einige Funktionen hinzugefügt.
Ich habe kleine Änderungen an der ursprünglichen Datei app_httpd.c vorgenommen, um das Pin-Signal GPIO_NUM_2 über die Webschnittstelle zu steuern. In der Beschreibung des Moduls geht es zwar um die Verwendung von Pins für die Anforderungen einer SD-Karte, aber ich verwende sie nicht, sodass ich diese Pins verwenden kann.
void app_httpd_main()
{
gpio_set_direction(GPIO_NUM_2, GPIO_MODE_OUTPUT);
static esp_err_t cmd_handler(httpd_req_t *req)
{
.......
// 736
else if(!strcmp(variable, "gpio2")) {
if (val == 0)
gpio_set_level(GPIO_NUM_2, 0);
else
gpio_set_level(GPIO_NUM_2, 1);
}
Für die Fernbedienung habe ich mich für ein unkompliziertes Node-Red-Panel entschieden, das auf einem Raspberry Pi läuft.
Es ist uns gelungen, das Videostream-Bild in den Vorlagenknoten einzubetten:
<iframe
src="http://192.168.1.61"
width="300" height="300">
</iframe>
Ein Punkt ist hier wichtig: Es ist notwendig, http einzubetten, im Fall von https gibt es Probleme mit der Content-Security-Policy. Wenn in diesem Fall Probleme auftreten, können Sie versuchen, Header hinzuzufügen:
<script>
var meta = document.createElement('meta');
meta.httpEquiv = "Content-Security-Policy";
meta.content = "default-src * 'unsafe-inline' 'unsafe-eval'; script-src * 'unsafe-inline' 'unsafe-eval'; connect-src * 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src *; style-src * 'unsafe-inline';";
document.getElementsByTagName('head')[0].appendChild(meta);
</script>
Um den GPIO_NUM_2-Pin des ESP32-CAM-Moduls zu steuern, sollte nach Änderungen an der Firmware die folgende http GET-Anforderung ausgeführt werden:
http://192.168.1.61/control?var=gpio2&val=1 // 0
Auf der Panel-Oberfläche ist dies der Weckschalter. Im Worker-Thread sieht es so aus, als ob
die Anforderungsfunktion:
var newMsg = {}
var i = msg.payload ? 1 : 0;
newMsg.query = "control?var=gpio2&val=" + i
node.send(newMsg)
Einstellungen des http-Anforderungsknotens:
Andere Parameter und Status werden über MQTT übertragen
Wi-Fi- und MQTT-Konnektivität
Ich werde Beispiele mit dem Arduino-Framework geben, da ich auch damit experimentiert habe. Aber am Ende habe ich eine funktionierende Anwendung auf ESP-IDF.
#Include <WiFi.h> -Header
Wi-Fi-Verbindungsfunktion für das Arduino-Framework
void setup_wifi()
{
Serial.println("Starting connecting WiFi.");
delay(1000);
for (int8_t i = 0; i < 3; i++)
{
WiFi.begin(ssid, password);
uint32_t start = millis();
while (WiFi.status() != WL_CONNECTED && ((millis() - start) < 4000))
{
Serial.print(".");
delay(500);
}
if (WiFi.status() == WL_CONNECTED)
{
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
return;
}
else
{
Serial.println("Connecting Failed");
//WiFi.reconnect(); // this reconnects the AP so the user can stay on the page
}
}
}
Die Funktion enthält seitdem eine Schleife für drei Iterationen Häufig kann beim ersten Versuch keine Verbindung hergestellt werden, und es wird endlos auf den Status WL_CONNECTED gewartet. Vielleicht können Sie es noch auf andere Weise lösen, aber es funktioniert so.
Die Verbindung zum MQTT für das Arduino-Framework erfolgt über die Bibliothek github.com/knolleary/pubsubclient.git .
Um die Bibliothek verwenden zu können, müssen Sie den Header #include <PubSubClient.h> einfügen
MQTT-Verbindungsfunktion
bool setup_mqtt()
{
if (WiFi.status() == WL_CONNECTED)
{
if (!client.connected())
{
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
Serial.print("Connecting to MQTT server ");
Serial.print(mqtt_server);
Serial.println("...");
String clientId = "ESP32_car_client";
if (client.connect(clientId.c_str()))
{
Serial.println("Connected to MQTT server ");
//subscribing to topics
client.subscribe("esp32/car/#");
client.subscribe("esp32/camera/#");
return true;
}
else
{
Serial.println("Could not connect to MQTT server");
return false;
}
}
return false;
}
Zuerst überprüfen wir, ob wir mit Wi-Fi verbunden sind, und stellen dann eine Verbindung zum Broker client.setServer (mqtt_server, 1883) her.
Und setzen Sie die Rückruffunktion client.setCallback (Rückruf);
MQTT-Rückruffunktion
void callback(char *topic, byte *payload, unsigned int length)
{
Serial.println("Message arrived ");
memset(payload_buf, 0, 10);
for (int i = 0; i < length; i++)
{
payload_buf[i] = (char)payload[i];
}
command_t mqtt_command = {
.topic = topic,
.message = payload_buf};
xQueueSend(messageQueue, (void *)&mqtt_command, 0);
}
Abonnieren Sie bei erfolgreicher Verbindung Themen
client.subscribe("esp32/car/#");
client.subscribe("esp32/camera/#");
In einigen Fällen wurde die MQTT-Verbindung unterbrochen, sodass der Aufgabe für regelmäßige Abfragen eine Überprüfung hinzugefügt wurde.
Regelmäßige Abfrageaufgabe
void pollingTask(void *parameter)
{
int32_t start = 0;
while (true) {
if (!client.connected()) {
long now = millis();
if (now - start > 5000) {
start = now;
// Attempt to reconnect
if (setup_mqtt()) {
start = 0;
}
}
}
else {
client.loop();
int val = digitalRead(WAKEUP_PIN);
if (val == LOW) {
Serial.println("Going to sleep now");
esp_deep_sleep_start();
}
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
Ein Beispiel für die Verbindung mit Wi-FI und MQTT über ESP-IDF wurde im vorherigen Artikel beschrieben. Bei der
Verwendung von ESP-IDF traten beim Herstellen einer Verbindung mit Wi-Fi und MQTT keine Störungen auf. Eine Nuance bei der Verarbeitung von Daten aus einem MQTT-Thema in der Funktion esp_err_t mqtt_event_handler (Ereignis esp_mqtt_event_handle_t): Wenn der Ereignistyp MQTT_EVENT_DATA ist, sollten Sie die Parameter event-> topic_len und event-> data_len berücksichtigen und den Namen des Themas und sonst die Daten der genauen Länge erhalten. Zu diesem Zweck können wir Pufferarrays erstellen oder Speicher dynamisch zuweisen (und dann freigeben) und beispielsweise die Daten kopieren
strncpy(topic, event->topic, event->topic_len);
strncpy(data, event->data, event→data_len);
Das Senden von Daten an ein Thema erfolgt mit der Funktion esp_mqtt_client_publish
esp_mqtt_client_publish(client, topics[i], topic_buff[i], 0,0,0);
HC-SR04 Datenverarbeitung für Ultraschallsensoren
HC-SR04 ist ein billiger und beliebter Sensor für die Entwicklung von Mikrocontroller-Geräten. Wie immer gibt es im Internet viel Material zu diesem Thema: hier und hier. Die Beschreibung kann auch hier eingesehen werden, und ein kurzes Datenblatt hier.
Kurz gesagt, um mit der Entfernungsmessung zu beginnen, müssen Sie ein hohes Signal mit einer Dauer von 10 μs an den Trig-Pin anlegen. Dies veranlasst den Sensor, 8 Zyklen eines 40-kHz-Ultraschallimpulses zu senden und auf den reflektierten Ultraschallimpuls zu warten. Wenn der Wandler ein Ultraschallsignal vom Empfänger erkennt, setzt er den Echoausgang hoch und verzögert sich um eine Periode (Breite) proportional zur Entfernung. Um die Entfernung zu berechnen, müssen Sie die Formel berechnen:
distance = duration * 340 / = duration * 0.034 /,
340 m / s - die Geschwindigkeit der Schallausbreitung in der Luft.
Im Arduino-Framework können Sie mit der Funktion pulsIn die Pulsdauer in μs ermitteln.
Für ESP-IDF gibt es ein Bibliotheksprojekt für ESP-IDF- Komponenten, das auch eine Ultraschallkomponente für HC-SR04 enthält.
Beispielcode
esp_err_t ultrasonic_measure_cm(const ultrasonic_sensor_t *dev, uint32_t max_distance, uint32_t *distance)
{
CHECK_ARG(dev && distance);
PORT_ENTER_CRITICAL;
// Ping: Low for 2..4 us, then high 10 us
CHECK(gpio_set_level(dev->trigger_pin, 0));
ets_delay_us(TRIGGER_LOW_DELAY);
CHECK(gpio_set_level(dev->trigger_pin, 1));
ets_delay_us(TRIGGER_HIGH_DELAY);
CHECK(gpio_set_level(dev->trigger_pin, 0));
// Previous ping isn't ended
if (gpio_get_level(dev->echo_pin))
RETURN_CRITICAL(ESP_ERR_ULTRASONIC_PING);
// Wait for echo
int64_t start = esp_timer_get_time();
while (!gpio_get_level(dev->echo_pin))
{
if (timeout_expired(start, PING_TIMEOUT))
RETURN_CRITICAL(ESP_ERR_ULTRASONIC_PING_TIMEOUT);
}
// got echo, measuring
int64_t echo_start = esp_timer_get_time();
int64_t time = echo_start;
int64_t meas_timeout = echo_start + max_distance * ROUNDTRIP;
while (gpio_get_level(dev->echo_pin))
{
time = esp_timer_get_time();
if (timeout_expired(echo_start, meas_timeout))
RETURN_CRITICAL(ESP_ERR_ULTRASONIC_ECHO_TIMEOUT);
}
PORT_EXIT_CRITICAL;
*distance = (time - echo_start) / ROUNDTRIP;
return ESP_OK;
}
Eine Erklärung des Algorithmus finden Sie in den Kommentaren. Die Impulsdauer wird in der while-Schleife gemessen, während der Signalpegel am Echo-Pin hoch ist (nachdem // Echo erhalten wurde, gemessen), wonach der Abstand gemessen wird
*distance = (time - echo_start) / ROUNDTRIP
Der Koeffizient für die Ermittlung des Abstands in Zentimetern ROUNDTRIP = 58.
Im Arduino-Framework sieht es noch einfacher aus
Beispielcode
#include "ultrasonic.h"
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
#define PORT_ENTER_CRITICAL portENTER_CRITICAL(&mux)
#define PORT_EXIT_CRITICAL portEXIT_CRITICAL(&mux)
Ultrasonic::Ultrasonic() {
pinMode(GPIO_NUM_33, OUTPUT);
pinMode(GPIO_NUM_26, INPUT);
}
uint32_t Ultrasonic::calculateDistance() {
PORT_ENTER_CRITICAL;
digitalWrite(GPIO_NUM_33, LOW);
delayMicroseconds(2);
digitalWrite(GPIO_NUM_33, HIGH);
delayMicroseconds(10);
digitalWrite(GPIO_NUM_33, LOW);
duration = pulseIn(GPIO_NUM_26, HIGH);
PORT_EXIT_CRITICAL;
distance = duration / 58;
return distance;
}
uint32_t Ultrasonic::getDistance() {
return distance;
}
Es wurde versucht, die Ultraschall-ESP-IDF-Bibliothek für das ESP32-Arduino-Projekt zu verwenden, aber dieser Fall funktioniert bis zum ersten Sensorfehler. Warum so, konnte man nicht genau herausfinden. Ein Sensorfehler ist eine periodische Fehleinschätzung von Impulsen und die Ausgabe falscher Messwerte. In den berechneten Zahlen sieht es nach einem Abstand von mehr als 20.000 cm aus. In den Foren wird angegeben, dass dies auf einen Sensor von schlechter Qualität zurückzuführen ist (chinesische Kopie).
Geschwindigkeitsmessung mit optischen Sensoren
Das optische Modul zum Lesen von Impulsen basiert auf dem Komparator LM393 und einem Schlitzsensor. Entwickelt für die Verwendung mit Rasterscheiben, die über die Welle eines Getriebes oder Elektromotors passen.
Wie üblich gibt es bereits Artikel zu diesem Thema: digitrode.ru , mirrobo.ru und arduino-kit.ru .
Sensorschaltung:
Im Arduino-Framework berechnen wir die Geschwindigkeit wie folgt:
- Definieren Sie beispielsweise die Variable (Struktur) des Zählers
typedef struct {
int encoder_pin = ENCODER_PIN; // pulse output from the module
unsigned int rpm = 0; // rpm reading
volatile byte pulses = 0; // number of pulses
unsigned long timeold = 0;
unsigned int pulsesperturn = 20;
} pulse_t;
Dann müssen wir in der Setup-Funktion den Eingangspin registrieren und ihn unterbrechen.
pinMode(pulse_struct.encoder_pin, INPUT);
attachInterrupt(pulse_struct.encoder_pin, counter, FALLING);
Als nächstes wird die Anzahl der Umdrehungen pro Minute berechnet
pulse_struct.rpm =
(60 * 1000 / pulse_struct.pulsesperturn )/
(1000)* pulse_struct.pulses;
Beispielcode
void pulseTask(void *parameters) {
sensor_data_t data;
data.sensor = OPTICAL_SENSOR;
portBASE_TYPE xStatus;
while (true) {
//Don't process interrupts during calculations
detachInterrupt(0);
pulse_struct.rpm =
(60 * 1000 / pulse_struct.pulsesperturn )/
(1000)* pulse_struct.pulses;
pulse_struct.pulses = 0;
data.value = pulse_struct.rpm;
//Restart the interrupt processing
attachInterrupt(0, counter, FALLING);
Serial.print("optical: ");
Serial.println(data.value);
//Sending data to sensors queue
xStatus = xQueueSend(sensorQueue, (void *)&data, 0);
if( xStatus != pdPASS ) {
printf("Could not send optical to the queue.\r\n");
}
taskYIELD();
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
In ESP-IDF können Sie zu diesem Zweck den Hardware-Zähler PCNT verwenden, der im vorherigen Artikel beschrieben wurde .
Beispielcode der zu verarbeitenden Aufgabe
typedef struct {
uint16_t delay; //delay im ms
int pin;
int ctrl_pin;
pcnt_channel_t channel;
pcnt_unit_t unit;
int16_t count;
} speed_sensor_params_t;
void pulseTask(void *parameters) {
sensor_data_t data_1;
sensor_data_t data_2;
data_1.sensor = OPTICAL_SENSOR_1;
data_2.sensor = OPTICAL_SENSOR_2;
portBASE_TYPE xStatus;
speed_sensor_params_t params_1 = {
.delay = 100,
.pin = ENCODER_1_PIN,
.ctrl_pin = GPIO_NUM_0,
.channel = PCNT_CHANNEL_0,
.unit = PCNT_UNIT_0,
.count = 0,
};
ESP_ERROR_CHECK(init_speed_sensor(¶ms_1));
speed_sensor_params_t params_2 = {
.delay = 100,
.pin = ENCODER_2_PIN,
.ctrl_pin = GPIO_NUM_1,
.channel = PCNT_CHANNEL_0,
.unit = PCNT_UNIT_1,
.count = 0,
};
ESP_ERROR_CHECK(init_speed_sensor(¶ms_2));
while(true) {
data_1.value = calculateRpm(¶ms_1);
data_2.value = calculateRpm(¶ms_2);
sensor_array[OPTICAL_SENSOR_1] = data_1.value;
sensor_array[OPTICAL_SENSOR_2] = data_2.value;
printf("speed 1 = %d\n", data_1.value);
printf("speed 2 = %d\n", data_2.value);
xStatus = xQueueSend(sensorQueue, (void *)&data_1, 0);
xStatus = xQueueSend(sensorQueue, (void *)&data_2, 0);
if( xStatus != pdPASS ) {
printf("Could not send optical to the queue.\r\n");
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
PWM-Steuerung
Informationen zur Steuerung von Servoantrieben auf Arduino finden Sie unter developer.alexanderklimov , wiki.amperka.ru .
Wie in der obigen Quelle angegeben: "Ein Servo ist ein Mechanismus mit einem Elektromotor, der sich in einen bestimmten Winkel drehen und die aktuelle Position halten kann." In der Praxis handelt es sich um eine Pulsweitenmodulation, bei der der Drehwinkel des Aktuators von der Signalimpulsbreite abhängt.
Für ESP32 in einem Arduino-Framework können Sie die ESP32Servo- Bibliothek verwenden.
Dazu verbinden wir den Header
#include <ESP32Servo.h>
Erstellen Sie ein Objekt
Servo servo_horisontal;
Wir geben den Ausgangspin an
servo_horisontal.attach(SERVO_CAM_HOR_PIN);
Danach können wir den erforderlichen Wert des Rotationsbetrags aufschreiben
servo_horisontal.write(value);
Die PWM-Steuerung für andere Gerätetypen im Arduino-Framework erfolgt mithilfe der Bibliothek esp32-hal-ledc.h. ESP32-
Mikrocontroller unterstützen die Standardfunktion Arduino analogWrite () für PWM nicht. Stattdessen werden Funktionen
bereitgestellt : ledcSetup (Kanal, Frequenz, Auflösungsbits) - gibt den Kanal, die Frequenz und die Auflösung an
ledcAttachPin (GPIO, Kanal) - zeigt den Port und den Kanal an
ledcWrite (Kanal, Tastverhältnis) - zeigt den Kanal und das Tastverhältnis des PWM-Signals an
Beispiele können gesehen werden,
wie Wie der Name schon sagt, wurden die Funktionen ursprünglich zur Steuerung von LED-Modulen entwickelt, sie werden jedoch auch für andere Zwecke verwendet.
Im ESP-IDF-Framework wird der Servoantrieb auf die gleiche Weise gesteuert wie die Kommutatorsteuerung mithilfe des MCPWM-Moduls, wie im vorherigen Artikel beschrieben. Ein Beispiel für die Steuerung eines MCPWM-Servomotors finden Sie hier
Beispielcode
static uint32_t servo_per_degree_init(uint32_t degree_of_rotation)
{
uint32_t cal_pulsewidth = 0;
cal_pulsewidth = (SERVO_MIN_PULSEWIDTH + (((SERVO_MAX_PULSEWIDTH - SERVO_MIN_PULSEWIDTH) * (degree_of_rotation)) / (SERVO_MAX_DEGREE)));
return cal_pulsewidth;
}
void mcpwm_example_servo_control(void *arg)
{
uint32_t angle, count;
//1. mcpwm gpio initialization
mcpwm_example_gpio_initialize();
//2. initial mcpwm configuration
printf("Configuring Initial Parameters of mcpwm......\n");
mcpwm_config_t pwm_config;
pwm_config.frequency = 50; //frequency = 50Hz, i.e. for every servo motor time period should be 20ms
pwm_config.cmpr_a = 0; //duty cycle of PWMxA = 0
pwm_config.cmpr_b = 0; //duty cycle of PWMxb = 0
pwm_config.counter_mode = MCPWM_UP_COUNTER;
pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //Configure PWM0A & PWM0B with above settings
while (1) {
for (count = 0; count < SERVO_MAX_DEGREE; count++) {
printf("Angle of rotation: %d\n", count);
angle = servo_per_degree_init(count);
printf("pulse width: %dus\n", angle);
mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, angle);
vTaskDelay(10); //Add delay, since it takes time for servo to rotate, generally 100ms/60degree rotation at 5V
}
}
}
Jene. Wir müssen das Modul mit der Funktion mcpwm_init (MCPWM_UNIT_0, MCPWM_TIMER_0, & pwm_config) initialisieren. Stellen Sie
dann den Winkelwert
mcpwm_set_duty_in_us (MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, Winkel) ein.
Beispiele für die Verwendung des MCPWM-Moduls für verschiedene Laufwerkstypen finden Sie auf github .
Ein Beispiel für eine bürstenbehaftete Motorsteuerung wurde auch im vorherigen Artikel vorgestellt.
Es ist zu beachten, dass eine solche Plattform eine differenziell gesteuerte nicht- holonome Plattform istSystem. Die Leistung der Motoren ist unterschiedlich, daher müssen Sie für einen von ihnen einen Software-Offset festlegen, um eine gleichmäßige Drehzahl zu gewährleisten. Sie können die Theorie unter robotosha.ru robotosha.ru/robotics/robot-motion.html kennenlernen . Zur optimalen Steuerung von Getriebemotoren wird ein PID-Algorithmus mit Rückmeldung in Form von optischen Sensoren verwendet. Die Beschreibung des Algorithmus wird hier und hier vorgestellt .
Eine Beschreibung der Bewegungsgleichungen sowie der Steuerungsalgorithmen würde den Rahmen dieses Artikels sprengen. Die Differentialkinematik ist noch nicht im Code implementiert.
Schlafmodi
Gemäß der Dokumentation sowie der Beschreibung im Artikel kann der ESP32 zwischen verschiedenen Leistungsmodi wechseln:
- Aktiver Modus
- Modem-Ruhemodus
- Leichter Schlafmodus
- Tiefschlafmodus
- Ruhezustand
Die Tabelle zeigt die Unterschiede im Stromverbrauch in verschiedenen Modi.
Ich habe den Tiefschlafmodus aktiviert, wenn kein hohes Signal am GPIO_NUM_13-Pin vorhanden ist
gpio_set_direction(WAKEUP_PIN, GPIO_MODE_INPUT);
esp_sleep_enable_ext0_wakeup(WAKEUP_PIN,1); //1 = High, 0 = Low
In Abwesenheit eines externen Einflusses habe ich den 10k-Eingang mit einem Widerstand auf 3,3 V hochgezogen, obwohl dies in der Software möglich ist. Und bei der periodischen Abfrage überprüfe ich den Zustand des Eingangssignals
if(!gpio_get_level(WAKEUP_PIN)) {
printf("Going to sleep now\n");
esp_deep_sleep_start();
}
Dies vervollständigt die Beschreibung. Ein praktisches Beispiel für die Verwendung von ESP32-Modulen mit verschiedenen Peripheriegeräten wurde gezeigt. Einige Fragen der Softwareimplementierung und des Vergleichs von ESP-IDF- und Arduino-Ansätzen werden ebenfalls angesprochen.