組み立てられた構造は次のようになります
コンポーネント
ベースは、モバイル2デッキロボプラットフォーム カーシャーシ2WDミニキット
プラットフォームの寸法:135 mm x 135 mm x 80 mm
ドライブは、ギアボックス付きの2つの標準モーターホイールと、速度センサー用のラスターディスク付きのDCモーターです。
- 定格電流:最大250mA 3.6Vの電圧で
- トルク800g / cm(6V電圧で)
- 供給電圧:6〜8 V
- 無負荷速度:170 rpm(3.6 Vで)
- ギア比:1:48
- アクスルが両側に出てきます
- 車軸径:5mm
- 寸法:64x20x20 mm
- 重量:26g
MX1508モジュールがモータードライバー として選択されまし
た。モジュールについては、ここで読むことができ
ます。技術パラメーター:
- 供給電圧:2〜10 V
- チャネルあたりの動作中のドライバー:1.5 A(ピーク電流2.5 A、10秒以内)
- ロジック入力:5V
- 寸法:24.7 x 21 x 0.5mm
IPカメラの水平および垂直移動には、人気のあるSG902kgサーボモーターが 選択されてい
ます。次の仕様がメーカーのWebサイトに掲載されています。
- 重量:9g
- 寸法:23×12.2x29mm
- ストールトルク:1.8kg / cm(4.8v)
- ギアタイプ:POMギアセット
- 動作速度:0.1秒/ 60度(4.8v)
- 動作電圧:4.8v
- 温度範囲:0℃_55℃
- デッドバンド幅:1us
- 電源:外部アダプター経由
- サーボワイヤー長さ:25cm
- サーボプラグ:JR(JRと双葉に適合)
ウェブ
サイトにはFPVブラケットキットが選択されました。オンラインストアのホルダーの説明:「FPVを使用すると、FPVカメラを3つの平面に向けることができます。簡単な接続と操作により、プラットフォームをすばやく組み立てて、コントローラーまたはフライトコントローラーに接続できます。 EMAX 9g ES08AミニサーボまたはSG90サーボと組み合わせて使用します(一部変更あり)。
「いくつかの変更を加えて」-考慮に入れる必要があり、文字通りの意味でファイルを使用してセットを変更する必要がありました。しかし、3ドルのDIYの場合、それはほとんど何もありません。一部の人は、改訂でさえ役に立たず、サーボがサイズに収まらない、私の場合はすべてのルールに合わないと不満を漏らしました。 2つのSG90スライドを使用して、カメラを水平および垂直に移動します。 3Dプリンターでデザインして印刷するオプションも検討されましたが、これまではこのホルダーに立ち寄りました。
ESP32 CAMに基づくIPカメラ
説明されているように、「ESP32のI2Sサブシステムは、ダイレクトメモリアクセス用にRAMに直接接続された高速バスも提供します。簡単に言うと、ハードウェア制御下で並列データを送受信するようにESP32I2Sサブシステムを構成できます。」
それら。カメラを接続するために実装されているハードウェア制御下で並列データを送受信するようにI2SESP32インターフェイスを構成できます。このボードはSeeedStudioによって開発されており、価格はここでは$ 9.90ですが、ラジオ店では$ 8で販売されており、SeeedStudioだけが製造できるわけではないようです。
技術データ:
- 最小の802.11b / g / n Wi-Fi BTSoCモジュール
- 低電力の32ビットCPUは、アプリケーションプロセッサにも対応できます
- 最大160MHzのクロック速度、最大600DMIPSの要約計算能力
- 内蔵520KB SRAM、外部4MPSRAM
- UART / SPI / I2C / PWM / ADC / DACをサポート
- OV2640およびOV7670カメラ、内蔵フラッシュランプをサポートします。
- サポート画像WiFIアップロード
- TFカードをサポート
- 複数のスリープモードをサポートします。
- 埋め込まれたLwipとFreeRTOS
- STA / AP / STA + AP動作モードをサポート
- Smart Config / AirKissテクノロジーをサポートする
- シリアルポートのローカルおよびリモートファームウェアアップグレード(FOTA)のサポート
動力源
プラットフォームは、再充電せずに長い間自律電源から制御されていませんでした。したがって、1つのスロットを備えたUSB出力を備えた2A18650電源モジュールがソースとして選択されました。
仕様:
- バッテリータイプ:18650 Li-Ion(保護なし)
- 充電器電圧:5V〜8V
- 出力電圧:
- 3V-バッテリーから保護装置を介して直接
- 5V-ブーストコンバーターを介して。
- 最大出力電流:
- 出力3V-1A
- 出力5V-2A
- 最大充電電流:1A
- 入力コネクタタイプ:マイクロUSB
- 出力コネクタタイプ:USB-A
- 5Vコンシューマー-過負荷および短絡から
- 寸法:
- PCB:29.5 x 99.5 x 19mm
- デバイス全体:30 x 116 x 20mm
メインコントローラーにはESP-WROOM-32を選択しましたが、
先ほどESP32の特徴について詳しく説明しました。モジュールの基本的な特徴は次のとおりです。
- Xtensa LX632ビットデュアルコアマイクロプロセッサ最大240MHz
- フラッシュメモリ:4 MB
- ワイヤレス通信Wi-Fi802.11b / g / n最大150Mb / s、Bluetooth 4.2 BR / EDR / BLE
- STA / AP / STA + APモード、組み込みTCP / IPスタックをサポート
- GPIO 32(UART、SPI、I2C、I2Sインターフェイス、PWM、SDコントローラー、容量性タッチ、ADC、DACなど
- 電源:microUSBコネクタ(CP2102コンバータ)または出力経由
- ピンピッチ:2.54mm(ブレッドボードに挿入可能)
- ボードサイズ:5.2 x 2.8cm
二つの光学式エンコーダ「Nonameボード」が使用されている ように速度センサ電動車輪のラスターディスクの回転パルスをカウントする。
特徴:
- 供給電圧:3.3V-5V
- センサーの溝の幅:6 mm;
- 出力タイプ:アナログおよびデジタル
- インジケーター:出力ステータス
人気の超音波距離計のHC-SR04を使用した ために距離を測定します。
特長:
- 供給電圧:5V
- サイレントモードでの消費量:2mA
- 動作中の消費量:15 mA
- 距離範囲:2〜400 cm
- 有効視角:15
- 作業視角:30°
ソフトウェアの実装
最初のステップは、ESP32CAMモジュールを理解してフラッシュすることでした。
モジュールの操作の説明は、Harba、 ここ、 ここ、およびその他のリソースに記載されています。
ほとんどの記事では、ArduinoIDEを使用した簡単なフラッシュプロセスについて説明しています。ほとんどの場合、これで十分であり、最初はこのオプションでも問題ありませんでした。
ラジオ店では、ESP32-CAMモジュールはOV2640カメラと一緒に販売されているため、スケッチに小さな変更を加える必要があります。
// 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
また、Wi-FiアクセスポイントのSSIDとパスワードも指定します
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
私の場合、Webカメラが機能するための条件の1つは、Keeneticプロキシサーバーを介してビデオストリームを送信できることです。 KeenetikVivaホームルーターを使用しています。 KeenDNSサービスは、ホームWebリソースにドメイン名を提供します。しかし、驚いたことに、最初の試みは失敗しました。インターネット経由でリモートアクセスしようとすると、「ヘッダーフィールドが長すぎてサーバーが解釈できません」というエラーが表示されました。では、この問題私が最初に遭遇しました。この問題の解決策は、たとえばCONFIG_HTTPD_MAX_REQ_HDR_LEN構成を変更することです。
#define CONFIG_HTTPD_MAX_REQ_HDR_LEN 2048
Arduino IDE ESP32の場合、モジュールはすでにコンパイルされ、静的ライブラリとして表示されます。静的ライブラリは、パスに沿ってWindowsに配置されています-%userprofile%\ AppData \ Local \ Arduino15 \ packages \ esp32 \ hardware \ esp32 \ 1.0.4 \ tools \ sdk \
Justヘッダーのパラメーターを変更しても何も起こりません。
つまり、構成を変更するには、ESP-IDFライブラリを再コンパイルする必要があります。
解決策は、github.com / espressif / esp-whoプロジェクトのクローンを作成することでした。例のあるディレクトリで、camera_web_serverプロジェクトを見つけ、ヘッダーの最大長のパラメーターを変更し、Wi-Fi接続設定を指定することも忘れないでください。
プロジェクトをコンパイルするには、別のチェックボックスをインストールする必要がありました-ESP32のサポートアレイ 'rtc_gpio_desc'
プロジェクトのコンパイルとロードが正常に完了したら、ブラウザで対応するIPアドレスに移動し、Webカメラのインターフェイスを備えたページに移動します。
インターフェイスはArduinoの例に似ていますが、いくつかの機能が追加されています。
元のapp_httpd.cファイルに小さな変更を加えて、WebインターフェイスからのGPIO_NUM_2ピン信号を制御しました。モジュールの説明では、SDカードのニーズに合わせてピンを使用する方法について説明していますが、私は使用していないので、これらのピンを使用できます。
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);
}
リモートコントロールについては、Raspberrypiで実行される単純なNode-Redパネルを補いました。
ビデオストリームイメージをテンプレートノードに埋め込むことができました。
<iframe
src="http://192.168.1.61"
width="300" height="300">
</iframe>
ここで重要な点が1つあります。httpを埋め込む必要があります。httpsの場合、Content-Security-Policyに問題が発生します。この場合に問題が発生した場合は、ヘッダーを追加してみてください。
<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>
ESP32-CAMモジュールのGPIO_NUM_2ピンを制御するには、ファームウェアに変更を加えた後、次のhttpGET要求を実行する必要があります。
http://192.168.1.61/control?var=gpio2&val=1 // 0
パネルインターフェイスでは、これはウェイクアップスイッチです。ワーカースレッドでは
、リクエスト関数は次のようになります。
var newMsg = {}
var i = msg.payload ? 1 : 0;
newMsg.query = "control?var=gpio2&val=" + i
node.send(newMsg)
httpリクエストノードの設定:
その他のパラメータとステータスはMQTTを介して送信されます
Wi-FiおよびMQTT接続
Arduinoフレームワークも実験したので、使用例を示します。しかし、最終的には、ESP-IDFで動作するアプリケーションがあります。
#<WiFi.h>ヘッダーを含める
ArduinoフレームワークのWi-Fi接続機能
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
}
}
}
この関数には、3回の反復のループが含まれています。多くの場合、最初の試行で接続に失敗し、WL_CONNECTEDステータスを際限なく待ちます。たぶんあなたはまだ別の方法でそれを解決することができます、しかしそれはそのように働きます。
ArduinoフレームワークのMQTTへの接続は、github.com / knolleary /pubsubclient.gitライブラリを使用して行われます。
ライブラリを使用するには、ヘッダー#include <PubSubClient.h>を含める必要があります
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;
}
まず、Wi-Fiに接続していることを確認してから、ブローカーclient.setServer(mqtt_server、1883)に接続します。
そして、コールバック関数client.setCallback(callback);を設定します。
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);
}
接続に成功した場合は、トピックを購読してください
client.subscribe("esp32/car/#");
client.subscribe("esp32/camera/#");
MQTT接続が切断される場合があったため、定期的なポーリングタスクにチェックが追加されました。
定期的なポーリングタスク
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);
}
ESP-IDFを使用してWi-FIおよびMQTTに接続する例については、前の記事で説明しました。ESP
-IDFを使用する場合、Wi-FiおよびMQTTに接続するときにグリッチは発生しませんでした。esp_err_t mqtt_event_handler関数(esp_mqtt_event_handle_tイベント)でMQTTトピックからのデータを処理するときの1つのニュアンス:イベントタイプがMQTT_EVENT_DATAの場合、event-> topic_lenおよびevent-> data_lenパラメーターを考慮し、トピック名と正確に適切な長さのデータを考慮する必要があります。そうしないと、ゴミが発生します。これを行うには、たとえば、バッファアレイを作成するか、メモリを動的に割り当てて(次に解放して)、データをコピーします。
strncpy(topic, event->topic, event->topic_len);
strncpy(data, event->data, event→data_len);
トピックへのデータの送信は、esp_mqtt_client_publish関数を使用して行われます。
esp_mqtt_client_publish(client, topics[i], topic_buff[i], 0,0,0);
HC-SR04超音波センサーデータ処理
HC-SR04は、マイクロコンピューターデバイスを設計するための安価で人気のあるセンサーです。いつものように、このトピックに関する多くの資料がインターネット上にあります:こことここ。説明はここで、短いデータシートはここ で表示することもできます。
つまり、距離の測定を開始するには、10μsの持続時間の高信号をTrigピンに適用する必要があります。これにより、センサーが開始され、40 kHzの超音波パルスが8サイクル送信され、反射された超音波パルスが待機します。トランスデューサーが受信機からの超音波信号を検出すると、エコー出力を高く設定し、距離に比例した周期(幅)だけ遅延させます。距離を計算するには、次の式を計算する必要があります。
distance = duration * 340 / = duration * 0.034 /,
340 m / s-空気中の音の伝播速度。
Arduinoフレームワークでは、pulseIn関数を使用してパルス幅をμs単位で確認できます。ESP
-IDFの場合、HC-SR04用の超音波コンポーネントもあるESP-IDFコンポーネントライブラリプロジェクトがあります。
サンプルコード
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;
}
コメントにアルゴリズムの説明があります。パルス幅は、エコーピンの信号レベルが高い間(//エコーを取得した後、測定中)、whileループで測定され、その後、距離が測定されます。
*distance = (time - echo_start) / ROUNDTRIP
センチメートル単位の距離を取得するための係数ROUNDTRIP =58。Arduino
フレームワークでは、さらに簡単に見えます。
サンプルコード
#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;
}
ESP32 Arduinoプロジェクトに超音波ESP-IDFライブラリを使用する試みがありましたが、この場合は最初のセンサーグリッチまで機能します。なぜそうなのか、正確に知ることはできませんでした。センサーグリッチは、パルスの周期的な誤算と誤った読み取り値の発行であり、計算された図では、20,000 cmを超える距離のように見えます。フォーラムでは、これは低品質のセンサー(中国のコピー)が原因であると書いています。
光学センサーによる速度測定
光パルス読み取りモジュールは、LM393コンパレータとスロットセンサーに基づいています。ギアボックスまたは電気モーターのシャフトに適合するラスターディスクで使用するために設計されています。
いつものように、このトピックに関する記事はすでにあります:digitrode.ru、mirrobo.ru、およびarduino-kit.ru。
センサー回路:
Arduinoフレームワークでは、速度を次のように計算します。-
たとえば、カウンターの変数(構造)を定義します。
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;
次に、セットアップ機能で、入力ピンを登録して中断する必要があります
pinMode(pulse_struct.encoder_pin, INPUT);
attachInterrupt(pulse_struct.encoder_pin, counter, FALLING);
次に、1分あたりの回転数が計算されます
pulse_struct.rpm =
(60 * 1000 / pulse_struct.pulsesperturn )/
(1000)* pulse_struct.pulses;
サンプルコード
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);
}
}
ESP-IDFでは、この目的のために、前の記事で説明したハードウェアカウンターPCNTを使用できます。
処理中のタスクのサンプルコード
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制御
Arduinoでのサーボドライブの制御については、developer.alexanderklimov、wiki.amperka.ruで読むことができます。
上記の情報源で述べられているように、「サーボは、特定の角度に回転して現在の位置を保持できる電気モーターを備えたメカニズムです。」実際には、アクチュエータの回転角度が信号パルス幅に依存するパルス幅変調を扱っています。
Arduinoフレームワーク上のESP32の場合、ESP32Servo ライブラリを使用できます
。このために、ヘッダーを接続します。
#include <ESP32Servo.h>
オブジェクトを作成する
Servo servo_horisontal;
出力ピンを示します
servo_horisontal.attach(SERVO_CAM_HOR_PIN);
その後、回転量の必要な値を書き留めることができます
servo_horisontal.write(value);
Arduinoフレームワーク上の他のタイプのデバイスのPWM制御は、esp32-hal-ledc.hライブラリを使用して行われます。ESP32
マイクロプロセッサは、PWMの標準Arduino AnalogWrite()関数をサポートしていません。それらの代わりに、関数が
提供されます:ledcSetup(channel、freq、resolution_bits)-チャネル、周波数、および解像度を示します
ledcAttachPin(GPIO、channel)-ポートとチャネルを示します
ledcWrite(channel、dutycycle)-PWM信号のチャネルとデューティサイクルを示します
例を見る
方法名前が示すように、これらの機能は元々LEDモジュールを制御するために設計されましたが、他の目的にも使用されます。
ESP-IDFフレームワークでは、前の記事で説明したように、サーボドライブはMCPWMモジュールを使用したコミュテーター制御と同じ方法で制御されます。MCPWMサーボモーター制御の例はここで見ることができます
サンプルコード
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
}
}
}
それら。 mcpwm_init関数(MCPWM_UNIT_0、MCPWM_TIMER_0、およびpwm_config)を使用してモジュールを初期化する必要があります。
次に、角度値
mcpwm_set_duty_in_us(MCPWM_UNIT_0、MCPWM_TIMER_0、MCPWM_OPR_A、angle);を設定します。
さまざまなドライブタイプにMCPWMモジュールを使用する例は、githubにあります。
ブラシをかけたモーター制御の例も前の記事で紹介しました。
このようなプラットフォームは、差分制御された非ホロノミックであることに注意してください。システム。モーターには性能のばらつきがあるため、均一な速度を確保するには、モーターの1つにソフトウェアオフセットを設定する必要があります。robotosha.ru robotosha.ru/robotics/robot-motion.htmlで、この理論に精通することができます。ギア付きモーターを最適に制御するために、光学センサーの形でフィードバックを行うPIDアルゴリズムが使用されます。アルゴリズムの説明は、こことここに示されています。
運動方程式と制御アルゴリズムの説明は、この記事の範囲を超えています。微分運動学はまだコードに実装されていません。
スリープモード
よるドキュメント、ならびににおいて説明資料、 ESP32は、異なる電力モードの間で切り替えることができます。
- アクティブモード
- モデムスリープモード
- ライトスリープモード
- ディープスリープモード
- ハイバネーションモード
この表は、さまざまなモードでの消費電流の違いを示しています。
GPIO_NUM_13ピンにHigh信号がない場合に、ディープスリープモードを有効にしました
gpio_set_direction(WAKEUP_PIN, GPIO_MODE_INPUT);
esp_sleep_enable_ext0_wakeup(WAKEUP_PIN,1); //1 = High, 0 = Low
外部からの影響がない場合、ソフトウェアで可能ですが、抵抗を使用して10k入力を3.3Vに引き上げました。そして、定期的なポーリングのタスクでは、入力信号の状態をチェックします
if(!gpio_get_level(WAKEUP_PIN)) {
printf("Going to sleep now\n");
esp_deep_sleep_start();
}
これで説明は完了です。さまざまな周辺機器でESP32モジュールを使用する実際的な例が示されました。ソフトウェアの実装とESP-IDFとArduinoのアプローチの比較に関するいくつかの問題にも触れています。