Platform webcam ESP32

Ide untuk merakit platform seluler dengan kamera web di papan muncul hampir secara spontan. Saya menginginkan sesuatu seperti kamera IP di gudang otomatisasi rumah saya yang sederhana. Dan di sini ini bukan masalah harga atau kualitas, melainkan bisa disebut eksperimen kreatif. Berbagai artikel dan proyek DIY seperti ini dijadikan inspirasi.



Struktur yang dirakit terlihat seperti ini



gambar



Komponen



Alasnya adalah Sasis Mobil 2WD Mini Kit platform robo platform mobile. Dimensi platform: 135 mm x 135 mm x 80 mm Penggeraknya adalah dua roda motor standar dengan kotak roda gigi dan motor DC dengan disk raster untuk sensor kecepatan:



gambar











  • nilai saat ini: maks 250mA. pada tegangan 3,6 V.
  • torsi 800 g / cm (pada tegangan 6V)
  • tegangan suplai: 6 - 8 V.
  • kecepatan tanpa beban: 170 rpm (pada 3,6 V)
  • rasio roda gigi: 1:48
  • as roda keluar di kedua sisi
  • diameter poros: 5 mm
  • dimensi: 64x20x20 mm
  • berat: 26g




Modul MX1508 dipilih sebagai driver motor. Anda

dapat membaca tentang modul di sini



gambar



Parameter teknis:



  • Tegangan suplai: 2 - 10 V.
  • Penggerak yang bekerja per saluran: 1,5 A (arus puncak 2,5 A, tidak lebih dari 10 detik)
  • Masukan logika: 5V
  • Dimensi: 24,7 x 21 x 0,5mm




Untuk gerakan horizontal dan vertikal kamera IP, motor servo SG90 2kg yang populer telah dipilih.



gambar



Spesifikasi berikut disajikan di situs web pabrikan:



  • Berat: 9g
  • Dimensi: 23 × 12.2x29mm
  • Torsi kios: 1.8kg / cm (4.8v)
  • Jenis roda gigi: set roda gigi POM
  • Kecepatan operasi: 0.1sec / 60degree (4.8v)
  • Tegangan operasi: 4.8v
  • Rentang suhu: 0 ℃ _ 55 ℃
  • Lebar pita mati: 1us
  • Catu Daya: Melalui Adaptor Eksternal
  • kawat servo panjang: 25 cm
  • Steker Servo: JR (Cocok untuk JR dan Futaba)




Kit Braket FPV telah dipilih untuk webcam.



gambar



Deskripsi dudukan di toko online: “FPV akan memungkinkan Anda mengarahkan kamera FPV Anda dalam 3 bidang. Koneksi dan operasi sederhana akan memungkinkan Anda untuk dengan cepat merakit dan menghubungkan platform ke pengontrol atau pengontrol penerbangan. Digunakan bersama dengan Servo Mini EMAX 9g ES08A atau servos SG90 (dengan beberapa modifikasi). "

“Dengan beberapa modifikasi” - ini harus diperhitungkan, set harus dimodifikasi dengan file dalam arti literal. Tapi untuk DIY seharga $ 3, itu tidak seberapa. Beberapa mengeluh bahwa bahkan revisi tidak membantu, dan servos tidak sesuai ukurannya, dalam kasus saya, semua aturan. Dua slide SG90 digunakan untuk menggerakkan kamera secara horizontal dan vertikal. Pilihan untuk mendesain dan mencetak pada printer 3D juga dipertimbangkan, tetapi sejauh ini berhenti pada pemegang ini.



Kamera IP berdasarkan ESP32 CAM



gambar



Seperti dijelaskan: “ Subsistem I2S di ESP32 juga menyediakan bus kecepatan tinggi yang terhubung langsung ke RAM untuk Akses Memori Langsung. Sederhananya, Anda dapat mengonfigurasi subsistem ESP32 I2S untuk mengirim atau menerima data paralel di bawah kendali perangkat keras. ”

Itu. Anda dapat mengonfigurasi antarmuka I2S ESP32 untuk mengirim atau menerima data paralel di bawah kendali perangkat keras, yang diterapkan untuk menghubungkan kamera. Papan ini dikembangkan oleh Seeed Studio, harganya $ 9,90 di sini, tetapi di toko radio kami dijual seharga $ 8, ternyata tidak hanya Seeed Studio yang dapat memproduksinya.



Data teknis:



  • Modul SoC Wi-Fi BT 802.11b / g / n terkecil
  • CPU 32-bit daya rendah, juga dapat melayani prosesor aplikasi
  • Kecepatan clock hingga 160MHz , Ringkasan daya komputasi hingga 600 DMIPS
  • 520 KB SRAM internal, 4MPSRAM eksternal
  • Mendukung UART / SPI / I2C / PWM / ADC / DAC
  • Mendukung kamera OV2640 dan OV7670, lampu Flash Built-in.
  • Mendukung unggahan gambar WiFI
  • Mendukung kartu TF
  • Mendukung beberapa mode tidur.
  • Lwip dan FreeRTOS yang disematkan
  • Mendukung mode operasi STA / AP / STA + AP
  • Mendukung teknologi Smart Config / AirKiss
  • Dukungan untuk peningkatan versi firmware lokal dan jarak jauh port serial (FOTA)




Sumber tenaga



Platform tidak dikontrol dari catu daya otonom untuk waktu yang lama tanpa pengisian ulang. Oleh karena itu, modul catu daya 2A 18650 dengan output USB dengan satu slot dipilih sebagai sumber.



gambar



Spesifikasi:

  • Jenis baterai: 18650 Li-Ion (tanpa perlindungan)
  • Tegangan pengisi daya: 5V hingga 8V
  • Tegangan keluaran:
  • 3V - langsung dari baterai melalui perangkat pelindung
  • 5V - melalui konverter penguat.
  • Arus keluaran maksimum:
  • Keluaran 3V - 1A
  • Keluaran 5V - 2A
  • Arus pengisian maksimum: 1A
  • Jenis Konektor Input: micro-USB
  • Tipe Konektor Keluaran: USB-A
  • Konsumen 5V - dari kelebihan beban dan korsleting
  • Ukuran:
  • PCB: 29,5 x 99,5 x 19mm
  • Seluruh perangkat: 30 x 116 x 20mm




ESP-WROOM-32 dipilih sebagai pengendali



gambar



utama.Sebelumnya saya telah menjelaskan karakteristik ESP32 lebih detail. Berikut adalah karakteristik dasar dari modul tersebut:

  • Xtensa LX6 Mikroprosesor dual-core 32-bit hingga 240 MHz
  • Memori flash: 4 MB
  • Komunikasi nirkabel Wi-Fi 802.11b / g / n hingga 150 Mb / s, Bluetooth 4.2 BR / EDR / BLE
  • Mendukung mode STA / AP / STA + AP, tumpukan TCP / IP bawaan
  • GPIO 32 (antarmuka UART, SPI, I2C, I2S, PWM, pengontrol SD, sentuh kapasitif, ADC, DAC, dan lainnya
  • Catu daya: melalui konektor microUSB (konverter CP2102) atau output
  • Pin pitch: 2.54mm (dapat dimasukkan ke papan tempat memotong roti)
  • Ukuran papan: 5,2 x 2,8 cm




Dua encoder optik "Noname" digunakan sebagai sensor kecepatan untuk menghitung pulsa rotasi dari disk raster roda motor.



gambar



Karakteristik:

  • Tegangan suplai: 3.3V - 5V
  • Lebar alur sensor: 6 mm;
  • Jenis keluaran: analog dan digital
  • Indikator: status keluaran




Pengukur jarak ultrasonik HC-SR04 yang populer digunakan untuk mengukur jarak.



gambar



Fitur:

  • Tegangan suplai: 5V
  • Konsumsi dalam mode senyap: 2mA
  • Konsumsi selama operasi: 15 mA
  • Rentang jarak: 2-400 cm
  • Sudut pandang efektif: 15
  • Sudut pandang kerja: 30 °




Implementasi perangkat lunak



Langkah pertama adalah mengenal dan mem-flash modul ESP32 CAM.

Deskripsi bekerja dengan modul disajikan di Harba, di sini, di sini, dan di sumber daya lainnya.

Sebagian besar artikel menjelaskan proses flashing sederhana menggunakan Arduino IDE. Dalam kebanyakan kasus, ini sudah cukup, dan pada awalnya opsi ini juga baik-baik saja bagi saya.



gambar



Di toko radio, modul ESP32-CAM dijual dengan kamera OV2640, jadi perubahan kecil perlu dilakukan pada sketsa:



// 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




Dan juga tentukan SSID dan kata sandi untuk titik akses Wi-Fi



const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";




Salah satu syarat agar kamera web berfungsi dalam kasus saya adalah kemampuan untuk mengirimkan aliran video melalui server proxy Keenetic. Saya menggunakan router rumah Keenetik Viva. Layanan KeenDNS menyediakan nama domain ke sumber daya web rumah. Tapi yang mengejutkan saya, usaha pertama gagal. Saat mencoba mengakses dari jarak jauh melalui Internet, saya menerima pesan kesalahan "Bidang header terlalu panjang untuk ditafsirkan oleh server". Dengan masalah ini yang pertama kali saya temui. Solusi untuk masalah ini adalah dengan mengubah konfigurasi CONFIG_HTTPD_MAX_REQ_HDR_LEN, misalnya



#define CONFIG_HTTPD_MAX_REQ_HDR_LEN 2048




Dalam kasus Arduino IDE ESP32, modul sudah dikompilasi dan disajikan sebagai pustaka statis, yang terletak di Windows di sepanjang jalur -% userprofile% \ AppData \ Local \ Arduino15 \ packages \ esp32 \ hardware \ esp32 \ 1.0.4 \ tools \ sdk \

Just mengubah parameter di tajuk tidak akan menghasilkan apa-apa.

Artinya, untuk mengubah konfigurasi, kita perlu mengkompilasi ulang pustaka ESP-IDF.

Solusinya adalah dengan mengkloning proyek github.com/espressif/esp-who . Di direktori dengan contoh, kami menemukan proyek camera_web_server, mengubah parameter panjang header maksimum, dan juga tidak lupa menentukan pengaturan koneksi Wi-Fi.



gambar



Agar proyek dapat dikompilasi, kami harus menginstal kotak centang lain - Support array 'rtc_gpio_desc' untuk ESP32



gambar



Setelah kompilasi dan pemuatan proyek berhasil, buka alamat IP yang sesuai di browser dan buka halaman dengan antarmuka kamera web kami.



gambar



Antarmukanya mirip dengan contoh Arduino, tetapi beberapa fungsi telah ditambahkan.



Saya membuat perubahan kecil pada file app_httpd.c asli untuk mengontrol sinyal pin GPIO_NUM_2 dari antarmuka web. Meskipun uraian modul mengatakan tentang penggunaan pin untuk kebutuhan kartu SD, tapi saya tidak menggunakannya, jadi saya bisa menggunakan pin ini.



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);
    	}




Untuk remote control, saya membuat panel yang tidak rumit di Node-Red yang berjalan pada Raspberry pi.



gambar



Kami berhasil menyematkan gambar aliran video ke dalam node template:



<iframe 
    src="http://192.168.1.61"
    width="300" height="300">
</iframe>




Satu poin penting di sini: http harus disematkan, dalam kasus https akan ada masalah dengan Kebijakan-Keamanan-Konten. Jika masalah muncul dalam kasus ini, Anda dapat mencoba menambahkan header:



<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>




Untuk mengontrol pin GPIO_NUM_2 modul ESP32-CAM, setelah melakukan perubahan pada firmware, permintaan http GET berikut harus dilakukan:



http://192.168.1.61/control?var=gpio2&val=1 // 0




Pada antarmuka panel, ini adalah tombol bangun, di thread pekerja akan terlihat seperti ini di



gambar



mana fungsi permintaan:



var newMsg = {}
var i = msg.payload ? 1 : 0;
newMsg.query = "control?var=gpio2&val=" + i
node.send(newMsg)




Pengaturan node permintaan http:



gambar



Parameter dan status lain dikirim melalui MQTT



Konektivitas Wi-Fi dan MQTT



Saya akan memberikan contoh menggunakan kerangka Arduino, karena saya juga mencobanya. Tetapi pada akhirnya, saya memiliki aplikasi yang berfungsi di ESP-IDF.



#Include header <WiFi.h>



Fungsi koneksi Wi-Fi untuk kerangka Arduino
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
    }
  }
}






Fungsi ini berisi perulangan untuk tiga iterasi, sejak sering gagal untuk menyambung pada percobaan pertama, dan kemudian menunggu tanpa henti untuk status WL_CONNECTED. Mungkin Anda masih bisa menyelesaikannya dengan cara lain, tetapi cara kerjanya seperti itu.



Menghubungkan ke MQTT untuk kerangka Arduino dilakukan menggunakan pustaka github.com/knolleary/pubsubclient.git .



Untuk menggunakan pustaka, Anda perlu menyertakan header #include <PubSubClient.h>



Fungsi koneksi MQTT
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;
}






Pertama, kami memeriksa bahwa kami terhubung ke Wi-Fi, kemudian kami terhubung ke broker client.setServer (mqtt_server, 1883);



Dan mengatur fungsi callback client.setCallback (callback);



Fungsi panggilan balik MQTT
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);
}






Jika koneksi berhasil, berlangganan topik



client.subscribe("esp32/car/#");
client.subscribe("esp32/camera/#");




Ada beberapa kasus koneksi MQTT yang terputus, sehingga pemeriksaan ditambahkan ke tugas polling berkala.



Tugas polling berkala
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);
}






Contoh menghubungkan ke Wi-FI dan MQTT menggunakan ESP-IDF telah dijelaskan di artikel sebelumnya. Dalam



kasus menggunakan ESP-IDF, tidak ada gangguan saat menghubungkan ke Wi-Fi dan MQTT. Satu nuansa saat memproses data dari topik MQTT dalam fungsi esp_err_t mqtt_event_handler (peristiwa esp_mqtt_event_handle_t): ketika jenis peristiwa adalah MQTT_EVENT_DATA, Anda harus mempertimbangkan parameter peristiwa-> topic_len dan peristiwa-> data_len dan mengambil nama topik dan data dengan panjang yang tepat, jika tidak Untuk melakukan ini, kita dapat membuat array buffer atau mengalokasikan memori secara dinamis (kemudian membebaskannya), dan menyalin data, misalnya



strncpy(topic, event->topic, event->topic_len);
strncpy(data, event->data, event→data_len);




Mengirim data ke topik dilakukan menggunakan fungsi esp_mqtt_client_publish



esp_mqtt_client_publish(client, topics[i], topic_buff[i], 0,0,0);




Pemrosesan Data Sensor Ultrasonik HC-SR04



HC-SR04 adalah sensor yang murah dan populer untuk merancang perangkat mikrokontroler. Seperti biasa, ada banyak materi di Internet tentang topik ini: di sini dan di sini. Deskripsi juga dapat dilihat di sini, dan lembar data singkat di sini.

Singkatnya, untuk mulai mengukur jarak, Anda harus menerapkan sinyal tinggi dengan durasi 10 μs ke pin Trigonometri. Ini memulai sensor untuk mengirimkan 8 siklus pulsa ultrasonik 40 kHz dan menunggu pulsa ultrasonik yang dipantulkan. Saat transduser mendeteksi sinyal ultrasonik dari penerima, transduser akan menyetel output Echo tinggi dan ditunda selama periode (lebar) yang sebanding dengan jarak. Untuk menghitung jarak, Anda perlu menghitung rumus:



distance = duration * 340 / = duration * 0.034 /,



340 m / s - kecepatan propagasi suara di udara.



gambar



Dalam framework Arduino, fungsi pulseIn memungkinkan Anda mengetahui durasi pulsa dalam μs.

Untuk ESP-IDF terdapat proyek library Komponen ESP-IDF , yang juga memiliki komponen ultrasonik untuk HC-SR04.



Kode sampel
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;
}






Ada penjelasan tentang algoritme di komentar. Durasi pulsa diukur dalam while loop sementara level sinyal tinggi pada pin Echo (setelah // mendapat echo, pengukuran) setelah itu jarak diukur



*distance = (time - echo_start) / ROUNDTRIP


Koefisien untuk mendapatkan jarak dalam sentimeter ROUNDTRIP = 58.



Dalam kerangka Arduino terlihat lebih mudah



Kode sampel
#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;
}






Ada upaya untuk menggunakan pustaka ESP-IDF ultrasonik untuk proyek ESP32 Arduino, tetapi kasus ini berfungsi hingga kesalahan sensor pertama. Mengapa demikian, tidak mungkin untuk mengetahui dengan tepat. Kesalahan sensor adalah kesalahan kalkulasi berkala dalam pulsa dan penerbitan pembacaan palsu, dalam angka yang dihitung terlihat seperti jarak lebih dari 20.000 cm. Di forum mereka menulis bahwa ini karena sensor berkualitas buruk (salinan China).



Pengukuran kecepatan dengan sensor optik



Modul optik untuk membaca pulsa didasarkan pada komparator LM393 dan sensor slot. Didesain untuk digunakan dengan cakram raster yang dipasang di atas poros gearbox atau motor listrik.



Seperti biasa, sudah ada artikel tentang topik ini: digitrode.ru , mirrobo.ru , dan arduino-kit.ru .



Rangkaian sensor:



gambar



Dalam kerangka Arduino, kami menghitung kecepatan sebagai berikut:

- tentukan variabel (struktur) penghitung, misalnya

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;




Kemudian, dalam fungsi pengaturan, kita harus mendaftarkan pin input dan menginterupsinya



pinMode(pulse_struct.encoder_pin, INPUT);
attachInterrupt(pulse_struct.encoder_pin, counter, FALLING);




Selanjutnya, dihitung jumlah putaran per menit



pulse_struct.rpm = 
        (60 * 1000 / pulse_struct.pulsesperturn )/ 
        (1000)* pulse_struct.pulses;




Kode sampel
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);
   }
}






Di ESP-IDF, Anda dapat menggunakan penghitung perangkat keras PCNT, yang telah dijelaskan di artikel sebelumnya , untuk tujuan ini .



Kode contoh dari tugas yang sedang diproses
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(&params_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(&params_2));

    while(true) {
        data_1.value = calculateRpm(&params_1);
        data_2.value = calculateRpm(&params_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);
}
}






Kontrol PWM



Anda dapat membaca tentang mengontrol drive servo di Arduino di developer.alexanderklimov , wiki.amperka.ru .

Seperti yang dinyatakan dalam sumber di atas: "Servo adalah mekanisme dengan motor listrik yang dapat berputar ke sudut tertentu dan menahan posisinya saat ini." Dalam praktiknya, kita berurusan dengan modulasi lebar pulsa, di mana sudut rotasi aktuator bergantung pada lebar pulsa sinyal.



gambar



Untuk ESP32 pada kerangka Arduino, Anda dapat menggunakan perpustakaan ESP32Servo



Untuk ini, kami menghubungkan tajuknya



#include <ESP32Servo.h>




Buatlah sebuah objek



Servo servo_horisontal;




Kami menunjukkan pin keluaran



 servo_horisontal.attach(SERVO_CAM_HOR_PIN);




Setelah itu kita bisa menuliskan nilai jumlah rotasi yang dibutuhkan



servo_horisontal.write(value);




Kontrol PWM untuk jenis perangkat lain pada kerangka Arduino dilakukan menggunakan pustaka esp32-hal-ledc.h

Mikrokontroler ESP32 tidak mendukung fungsi analogWrite () Arduino standar untuk PWM. Alih-alih mereka, fungsi

disediakan : ledcSetup (saluran, frekuensi, resolusi_bits) - saluran, frekuensi dan resolusi

ditunjukkan ledcAttachPin (GPIO, saluran) - port dan saluran ditunjukkan

ledcWrite (saluran, dutycycle) - saluran dan siklus kerja sinyal PWM ditunjukkan

Contoh dapat dilihat

Bagaimana Seperti namanya, fungsi ini awalnya dirancang untuk mengontrol modul LED, tetapi juga digunakan untuk tujuan lain.



Dalam kerangka kerja ESP-IDF, drive servo dikontrol dengan cara yang sama seperti kontrol komutator menggunakan modul MCPWM, seperti yang dijelaskan di artikel sebelumnya. Contoh kontrol motor servo MCPWM dapat dilihat di sini



Kode sampel
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
        }
    }
}






Itu. kita perlu menginisialisasi modul menggunakan fungsi mcpwm_init (MCPWM_UNIT_0, MCPWM_TIMER_0, & pwm_config);

Dan kemudian atur nilai sudut

mcpwm_set_duty_in_us (MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, sudut);



Contoh penggunaan modul MCPWM untuk jenis drive yang berbeda dapat ditemukan di github .

Contoh kontrol motor yang disikat juga disajikan pada artikel sebelumnya .



Perlu dicatat bahwa platform semacam itu adalah nonholonomis yang dikontrol secara diferensialsistem. Motor memiliki kinerja yang bervariasi, jadi Anda harus menyetel offset perangkat lunak untuk salah satunya guna memastikan kecepatan yang seragam. Anda dapat mengenal teori ini di robotosha.ru robotosha.ru/robotics/robot-motion.html . Untuk kendali optimal motor roda gigi, algoritma PID dengan umpan balik berupa sensor optik digunakan. Deskripsi algoritma disajikan di sini dan di sini .

Penjelasan tentang persamaan gerak, serta algoritma kontrol, berada di luar cakupan artikel ini. Kinematika diferensial belum diimplementasikan dalam kode.



Mode tidur



Menurut dokumentasi , serta deskripsi dalam artikel, ESP32 dapat beralih di antara mode daya yang berbeda:

  • Mode aktif
  • Modem mode Tidur
  • Mode Tidur Ringan
  • Mode tidur nyenyak
  • Mode hibernasi




Tabel tersebut menunjukkan perbedaan konsumsi saat ini dalam berbagai mode.



gambar



Saya mengaktifkan mode Tidur Pulas jika tidak ada sinyal tinggi pada pin GPIO_NUM_13



gpio_set_direction(WAKEUP_PIN, GPIO_MODE_INPUT);
esp_sleep_enable_ext0_wakeup(WAKEUP_PIN,1); //1 = High, 0 = Low




Dengan tidak adanya pengaruh eksternal, saya menarik input 10k dengan resistor ke 3,3 V, meskipun mungkin dalam perangkat lunak. Dan dalam tugas polling berkala, saya memeriksa status sinyal input



if(!gpio_get_level(WAKEUP_PIN)) {
         printf("Going to sleep now\n");
        esp_deep_sleep_start();
    }




Ini akan menyimpulkan deskripsi. Contoh praktis penggunaan modul ESP32 dengan berbagai periferal ditampilkan. Beberapa masalah implementasi perangkat lunak dan perbandingan pendekatan ESP-IDF dan Arduino juga disinggung.



All Articles