Add ADC for motor current and battery voltage

master
Tom Wilson 4 years ago
parent 3b75bca5c3
commit 8c1f11d172

@ -39,6 +39,7 @@ typedef struct {
};
} motor_write_packet_t;
// Note that this structure is currently 124 bytes - _very_ close to the 128 (well, 126) byte I2C buffer limit.
typedef struct {
float roller_1_speed;
float roller_2_speed;
@ -49,6 +50,10 @@ typedef struct {
float motor_1_duty;
float motor_2_duty;
float motor_3_duty;
float motor_1_current;
float motor_2_current;
float motor_3_current;
float system_voltage;
motor_control_t motor_1_control;
motor_control_t motor_2_control;
motor_control_t motor_3_control;
@ -57,4 +62,7 @@ typedef struct {
motor_parameters_t motor_3_params;
} motor_status_packet_t;
//In VSCode, can check the struct size by uncommenting the following and hovering over "sizeof":
//size_t struct_s = sizeof(motor_status_packet_t);
#endif

@ -0,0 +1,91 @@
#include "adc_read.h"
#include "io.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"
#define SYS_VOLTS_PER_ADC_MV ((((2.2+10.0)/2.2)/1000.0)*1.042)
#define MOTOR_AMPS_PER_ADC_MV ((2.5/1000.0)*1.042)
#define ADC_TASK_STACK_SIZE 2048
static xQueueHandle motor_current_queue[3];
static xQueueHandle system_voltage_queue;
float get_motor_current(motor_id_t motor_id) {
float motor_current;
xQueuePeek(motor_current_queue[motor_id], &motor_current, 0);
return motor_current;
}
float get_system_voltage() {
float system_voltage;
xQueuePeek(system_voltage_queue, &system_voltage, 0);
return system_voltage;
}
static esp_adc_cal_characteristics_t adc1_11db_chars;
static esp_adc_cal_characteristics_t adc1_6db_chars;
static void motor_control_task(void *pvParameters) {
TickType_t xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
int adc_raw;
float result;
for (;;) {
adc_raw = adc1_get_raw(ADC_ROLLER1_IS);
result = esp_adc_cal_raw_to_voltage(adc_raw, &adc1_11db_chars) * MOTOR_AMPS_PER_ADC_MV;
xQueueOverwrite(motor_current_queue[0], &result);
adc_raw = adc1_get_raw(ADC_ROLLER2_IS);
result = esp_adc_cal_raw_to_voltage(adc_raw, &adc1_11db_chars) * MOTOR_AMPS_PER_ADC_MV;
xQueueOverwrite(motor_current_queue[1], &result);
adc_raw = adc1_get_raw(ADC_ROLLER3_IS);
result = esp_adc_cal_raw_to_voltage(adc_raw, &adc1_11db_chars) * MOTOR_AMPS_PER_ADC_MV;
xQueueOverwrite(motor_current_queue[2], &result);
adc_raw = adc1_get_raw(ADC_SYS_VOLTAGE);
result = esp_adc_cal_raw_to_voltage(adc_raw, &adc1_11db_chars) * SYS_VOLTS_PER_ADC_MV;
xQueueOverwrite(system_voltage_queue, &result);
// Suspend task until the next control loop iteration
vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(ADC_UPDATE_PERIOD_MS));
}
}
void adc_read_setup(void) {
// Allocate queues
motor_current_queue[0] = xQueueCreate(1, sizeof(float));
motor_current_queue[1] = xQueueCreate(1, sizeof(float));
motor_current_queue[2] = xQueueCreate(1, sizeof(float));
system_voltage_queue = xQueueCreate(1, sizeof(float));
// Prime queues
float initial_motor_current = 0.0;
xQueueOverwrite(motor_current_queue[0], &initial_motor_current);
xQueueOverwrite(motor_current_queue[1], &initial_motor_current);
xQueueOverwrite(motor_current_queue[2], &initial_motor_current);
float initial_system_voltage = 0.0;
xQueueOverwrite(system_voltage_queue, &initial_system_voltage);
// Init ADC
// If our ESP32 doesn't have calibration fuses set, this will use the default VREF value we give it here
esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1158, &adc1_11db_chars);
esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_6, ADC_WIDTH_BIT_12, 1158, &adc1_6db_chars);
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(ADC_ROLLER1_IS, ADC_ATTEN_DB_11);
adc1_config_channel_atten(ADC_ROLLER2_IS, ADC_ATTEN_DB_11);
adc1_config_channel_atten(ADC_ROLLER3_IS, ADC_ATTEN_DB_11);
adc1_config_channel_atten(ADC_SYS_VOLTAGE, ADC_ATTEN_DB_11);
// Kick off our ADC task
xTaskCreate(motor_control_task, "ADC", ADC_TASK_STACK_SIZE, NULL, 5, NULL);
}

@ -0,0 +1,14 @@
#ifndef adc_read_h
#define adc_read_h
#include "../common/shared_structs.h"
#define ADC_UPDATE_PERIOD_MS 100
void adc_read_setup(void);
float get_motor_current(motor_id_t m_id);
float get_system_voltage();
#endif

@ -3,6 +3,7 @@
#include "io.h"
#include "motor_control.h"
#include "roller_speed.h"
#include "adc_read.h"
#include "../common/shared_structs.h"
@ -26,6 +27,12 @@ void on_I2C_request() {
i2c_reply.motor_1_duty = get_motor_duty(MOTOR_1);
i2c_reply.motor_2_duty = get_motor_duty(MOTOR_2);
i2c_reply.motor_3_duty = get_motor_duty(MOTOR_3);
i2c_reply.motor_1_current = get_motor_current(MOTOR_1);
i2c_reply.motor_2_current = get_motor_current(MOTOR_2);
i2c_reply.motor_3_current = get_motor_current(MOTOR_3);
i2c_reply.system_voltage = get_system_voltage();
i2c_reply.motor_1_control = get_motor_control(MOTOR_1);
i2c_reply.motor_2_control = get_motor_control(MOTOR_2);
i2c_reply.motor_3_control = get_motor_control(MOTOR_3);

@ -1,6 +1,8 @@
#ifndef io_h
#define io_h
#include "soc/adc_channel.h"
// Many of the ESP-IDF functions require pins from the gpio_num_t enum
#define GPIO_ROLLER1_SPEED GPIO_NUM_5
#define GPIO_ROLLER2_SPEED GPIO_NUM_18
@ -12,9 +14,13 @@
#define GPIO_ROLLER2_PWM GPIO_NUM_27
#define GPIO_ROLLER3_PWM GPIO_NUM_14
#define GPIO_ROLLER1_IS GPIO_NUM_36
#define ADC_ROLLER1_IS ADC1_GPIO36_CHANNEL
#define GPIO_ROLLER2_IS GPIO_NUM_39
#define ADC_ROLLER2_IS ADC1_GPIO39_CHANNEL
#define GPIO_ROLLER3_IS GPIO_NUM_34
#define ADC_ROLLER3_IS ADC1_GPIO34_CHANNEL
#define GPIO_SYS_VOLTAGE GPIO_NUM_35
#define ADC_SYS_VOLTAGE ADC1_GPIO35_CHANNEL
#define GPIO_I2C_SDA GPIO_NUM_21
#define GPIO_I2C_SCL GPIO_NUM_22

@ -3,12 +3,14 @@
#include "motor_control.h"
#include "roller_speed.h"
#include "i2c_comms.h"
#include "adc_read.h"
void setup() {
Serial.setTimeout(1);
Serial.begin(57600);
roller_speed_setup();
adc_read_setup();
motor_control_setup();
i2c_comms_setup();
}

@ -13,7 +13,7 @@ that's been bundled out into its own FreeRTOS module (using the ESP IDF librarie
#include "io.h"
#include "shaft_speed.h"
#define MOTOR_STATUS_UPDATE_PERIOD_MS 500
#define MOTOR_STATUS_UPDATE_PERIOD_MS 250
#define WHEEL_FAN_STATUS_UPDATE_PERIOD_MS 1000 // also includes oil pressure sensor
#define BIN_STATUS_UPDATE_PERIOD_MS 3000
#define PIPE_PRESSURE_UPDATE_PERIOD_MS 2000
@ -303,17 +303,17 @@ void loop() {
// being driven with. [motor_current] is an estimated average current draw of the motor in amps (a float).
// Floats are given with 2 digits after the decimal (dynamic before the decimal)
sprintf(msg_buffer, "%lu %d %.2f %.3f %.3f %.2f 0.00", now, motor_status.motor_1_control.enabled,
sprintf(msg_buffer, "%lu %d %.2f %.3f %.3f %.2f %.2f", now, motor_status.motor_1_control.enabled,
motor_status.motor_1_control.desired_speed, motor_status.roller_1_speed, motor_status.roller_1_revs,
motor_status.motor_1_duty);
motor_status.motor_1_duty, motor_status.motor_1_current);
mqtt_client.publish("airseeder/status/roller1", msg_buffer, true);
sprintf(msg_buffer, "%lu %d %.2f %.3f %.3f %.2f 0.00", now, motor_status.motor_2_control.enabled,
sprintf(msg_buffer, "%lu %d %.2f %.3f %.3f %.2f %.2f", now, motor_status.motor_2_control.enabled,
motor_status.motor_2_control.desired_speed, motor_status.roller_2_speed, motor_status.roller_2_revs,
motor_status.motor_2_duty);
motor_status.motor_2_duty, motor_status.motor_2_current);
mqtt_client.publish("airseeder/status/roller2", msg_buffer, true);
sprintf(msg_buffer, "%lu %d %.2f %.3f %.3f %.2f 0.00", now, motor_status.motor_3_control.enabled,
sprintf(msg_buffer, "%lu %d %.2f %.3f %.3f %.2f %.2f", now, motor_status.motor_3_control.enabled,
motor_status.motor_3_control.desired_speed, motor_status.roller_3_speed, motor_status.roller_3_revs,
motor_status.motor_3_duty);
motor_status.motor_3_duty, motor_status.motor_3_current);
mqtt_client.publish("airseeder/status/roller3", msg_buffer, true);
sprintf(msg_buffer, "%lu %d %d %d %.2f %.2f %.2f", now, roller_ctrl[0].mode, roller_ctrl[1].mode,
@ -321,6 +321,9 @@ void loop() {
roller_ctrl[2].wheel_ratio);
mqtt_client.publish("airseeder/status/rollercontrol", msg_buffer, true);
sprintf(msg_buffer, "%lu %.2f", now, motor_status.system_voltage);
mqtt_client.publish("airseeder/status/battery", msg_buffer, true);
// Need to save the motor parameters somewhere, so that modification to one of them keeps the old ones
motor_parameters[0] = motor_status.motor_1_params;
motor_parameters[1] = motor_status.motor_2_params;

Loading…
Cancel
Save