/* Robot Controls Generate PWM signals to control motors. By: Alexander Bobkov Date: Dec 21, 2024 Updated: Jan 10, 2025 Jun 26, 2025 Jul 26, 2025 (ESP-IDF + MQTT + WiFi) built-in LED GPIO: 10 build-in push button GPIO: 3 ESP-PDF: v5.4.1 SPECS Voltage, DevBoard: 5V Voltage, Robot: 7.4V (2S LiPo battery) Current, standby: 300mA Current, motors: 850mA */ #include #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "driver/gpio.h" #include "driver/ledc.h" #include "driver/temperature_sensor.h" //#include "driver/mcpwm.h" #include "esp_log.h" #include "led_strip.h" #include "sdkconfig.h" /* ADC */ #include "rc.h" /* Motors Controls */ #include "motor_controls.h" /* System-wide controls */ #include "controls.h" #include "esp_adc/adc_continuous.h" /* ESP-NOW */ #include #include #include "freertos/semphr.h" #include "freertos/timers.h" #include "nvs_flash.h" #include "esp_random.h" #include "esp_event.h" #include "esp_log.h" #include "esp_crc.h" #include "esp_netif.h" #include "esp_now.h" #include "esp_mac.h" #include "esp_wifi.h" #include "mqtt.h" #include "esp_system.h" #include "espnow_config.h" #include "ultrasonic.h" #include "ina219.h" #include "config.h" static const char *TAG = "ESP IDF Robot"; #define I2C_PORT 0 #define I2C_ADDR 0x40 #define CONFIG_EXAMPLE_I2C_MASTER_SDA 3 #define CONFIG_EXAMPLE_I2C_MASTER_SCL 2 #define CONFIG_EXAMPLE_SHUNT_RESISTOR_MILLI_OHM 100 /* Use project configuration menu (idf.py menuconfig) to choose the GPIO to blink, or you can edit the following line and set a number here. */ // Retrieve values from configuration menu #define BLINK_GPIO CONFIG_BLINK_GPIO // 10 GPIO of on-board LED #define PUSH_BTN_GPIO CONFIG_BUTTON_GPIO // 8, not 3 GPIO of on-board push-button #define MTR_FL_GPIO 0 //CONFIG_MOTOR_FRONT_LEFT_GPIO // ADC #define ADC_ATTEN ADC_ATTEN_DB_11 #define ADC_BIT_WIDTH SOC_ADC_DIGI_MAX_BITWIDTH #define ADC_UNIT ADC_UNIT_1 #define ADC_CONV_MODE ADC_CONV_BOTH_UNIT// ADC_CONV_SINGLE_UNIT_1 #define ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE2 // ESP32C3 #define READ_LEN 1024//256 //#define ADC_GET_CHANNEL(p_data) ((p_data)->type2.channel) //#define ADC_GET_DATA(p_data) ((p_data)->type2.data) #define PROJ_X (1) // ADC1_CH1; 0 GPIO joystick, x-axis #define PROJ_Y (0) // ADC1_CH0; 1 GPIO joystick, y-axis #define NAV_BTN (8) // 8 GPIO joystick button #define _ADC_UNIT_STR(unit) #unit #define ADC_UNIT_STR(unit) _ADC_UNIT_STR(unit) uint32_t x_avg = 0, y_avg = 0; static TaskHandle_t led_task_handle; static TaskHandle_t s_task_handle; static TaskHandle_t m_task_handle; // Task for controlling motors PWMs static adc_channel_t channel[2] = {ADC_CHANNEL_0, ADC_CHANNEL_1}; static sensors_data_t buf; #define ESP_INTR_FLAG_DEFAULT 0 #define GPIO_INPUT_PIN_SEL ((1ULL< 0); ESP_ERROR_CHECK(ina219_init_desc(&dev, I2C_ADDR, I2C_PORT, CONFIG_EXAMPLE_I2C_MASTER_SDA, CONFIG_EXAMPLE_I2C_MASTER_SCL)); ESP_LOGI(TAG, "Initializing INA219"); ESP_ERROR_CHECK(ina219_init(&dev)); ESP_LOGI(TAG, "Configuring INA219"); ESP_ERROR_CHECK(ina219_configure(&dev, INA219_BUS_RANGE_16V, INA219_GAIN_0_125, INA219_RES_12BIT_1S, INA219_RES_12BIT_1S, INA219_MODE_CONT_SHUNT_BUS)); ESP_LOGI(TAG, "Calibrating INA219"); ESP_ERROR_CHECK(ina219_calibrate(&dev, (float)CONFIG_EXAMPLE_SHUNT_RESISTOR_MILLI_OHM / 1000.0f)); float bus_voltage, shunt_voltage, current, power; ESP_LOGI(TAG, "Starting the loop"); while (1) { ESP_ERROR_CHECK(ina219_get_bus_voltage(&dev, &bus_voltage)); ESP_ERROR_CHECK(ina219_get_shunt_voltage(&dev, &shunt_voltage)); ESP_ERROR_CHECK(ina219_get_current(&dev, ¤t)); ESP_ERROR_CHECK(ina219_get_power(&dev, &power)); /* Using float in printf() requires non-default configuration in * sdkconfig. See sdkconfig.defaults.esp32 and * sdkconfig.defaults.esp8266 */ printf("VBUS: %.04f V, VSHUNT: %.04f mV, IBUS: %.04f mA, PBUS: %.04f mW\n", bus_voltage, shunt_voltage * 1000, current * 1000, power * 1000); uint8_t channel; wifi_band_t band; esp_wifi_get_channel(&channel, NULL); esp_wifi_get_band(&band); printf("Wi-Fi Channel: %d, Band:%d\n", channel, band); //ESP_LOGE(TAG, "Wi-Fi Channel: %d, Band: %d", channel, band); vTaskDelay(pdMS_TO_TICKS(2500)); } } void app_main(void) { // Initialize NVS before Wi-Fi esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); // Use wifi_init() for ESP-NOW and Wi-Fi setup wifi_init(); // Initialize internal temperature sensor chip_sensor_init(); xTaskCreate(temp_sensor_task, "ESP32C3 Sensor", 2048, NULL, 15, NULL); // Initialize LED ledc_init(); int var = 8191; gpio_config_t io_conf = {}; // Configure on-board LED gpio_reset_pin(BLINK_GPIO); gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT); xTaskCreate(led_task, "LED", 2048, NULL, 15, NULL); // Configure on-board push button io_conf.intr_type = GPIO_INTR_POSEDGE; io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL; io_conf.mode = GPIO_MODE_INPUT; io_conf.pull_up_en = 1; gpio_config(&io_conf); gpio_set_intr_type(PUSH_BTN_GPIO, GPIO_INTR_NEGEDGE); gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); xTaskCreate(gpio_task, "GPIO task", 2048, NULL, 10, NULL); gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); gpio_isr_handler_add(PUSH_BTN_GPIO, gpio_isr_handler, (void*) PUSH_BTN_GPIO); // Configure navigation button io_conf.intr_type = GPIO_INTR_NEGEDGE; io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL; io_conf.mode = GPIO_MODE_INPUT; io_conf.pull_up_en = 1; gpio_config(&io_conf); gpio_set_intr_type(NAV_BTN, GPIO_INTR_NEGEDGE); gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); xTaskCreate(nav_key_task, "NAV Keys task", 2048, NULL, 10, NULL); gpio_isr_handler_add(NAV_BTN, gpio_isr_handler, (void*) NAV_BTN); configure_button(); printf("Added button interrupt"); mqtt_app_start(); // Initialize buffer with 0s buf.x_axis = 0; buf.y_axis = 0; buf.motor1_rpm_pcm = 0; esp_now_init(); esp_now_register_recv_cb((void*)onDataReceived); // ADC rc_adc_init(); xTaskCreate(rc_task, "RC", 2048, NULL, 5, NULL); // MOTORS motors_init(); ESP_ERROR_CHECK(i2cdev_init()); xTaskCreate(task, "test", configMINIMAL_STACK_SIZE * 8, NULL, 5, NULL); xTaskCreate(display_xy, "coordinates", configMINIMAL_STACK_SIZE * 8, NULL, 4, NULL); }