Add pipe pressure sensing and MQTT publishing

master
Tom Wilson 4 years ago
parent c3ce48f06b
commit 9582fd53af

@ -21,11 +21,17 @@ monitor_speed = 57600
[env:primary_esp32]
src_filter = +<primary-esp32/*> +<common/*>
lib_deps = plapointe6/EspMQTTClient@^1.13.3
lib_deps =
plapointe6/EspMQTTClient@^1.13.3
adafruit/Adafruit BusIO@^1.11.3
adafruit/Adafruit MPRLS Library@^1.2.0
[env:primary_esp32_ota]
src_filter = +<primary-esp32/*> +<common/*>
lib_deps = plapointe6/EspMQTTClient@^1.13.3
lib_deps =
plapointe6/EspMQTTClient@^1.13.3
adafruit/Adafruit BusIO@^1.11.3
adafruit/Adafruit MPRLS Library@^1.2.0
upload_protocol = espota
upload_port = airseeder.local
upload_flags = "--auth=87usc6rs"

@ -1,6 +1,9 @@
#include "Arduino.h"
#include "Wire.h"
// Annoyingly, we need to include SPI for the Adafuit Bus IO library to work
#include "Adafruit_MPRLS.h"
#include "SPI.h"
#include "io.h"
#include "i2c_comms.h"
@ -20,9 +23,13 @@ static TaskHandle_t i2c_comms_task_handle = NULL;
static SemaphoreHandle_t motor_status_semaphore;
static xQueueHandle motor_status_queue;
static SemaphoreHandle_t pipe_pressure_semaphore;
static xQueueHandle pipe_pressure_queue;
static xQueueHandle motor_control_queue;
static xQueueHandle motor_parameter_queue;
Adafruit_MPRLS mpr_sensor = Adafruit_MPRLS(-1, -1);
// Ask the I2C task to get a status update from the motor ESP32
void request_motor_status_update() {
@ -36,24 +43,54 @@ bool get_motor_status_update(motor_status_packet_t *status_packet) {
return (xQueueReceive(motor_status_queue, status_packet, 0) == pdTRUE);
}
// Ask the I2C task to get a status update from the motor ESP32
void request_pipe_pressure_update() {
xSemaphoreGive(pipe_pressure_semaphore);
// Wake up task
xTaskNotifyGive(i2c_comms_task_handle);
}
// Get a pipe pressure status update, if one exists. Returns True if a new update was copied out.
bool get_pipe_pressure_status_update(pipe_pressure_status_t *status_update) {
return (xQueueReceive(pipe_pressure_queue, status_update, 0) == pdTRUE);
}
// Ask the I2C task to send a control packet
void set_motor_control(motor_control_group_t new_motor_control){
void set_motor_control(motor_control_group_t new_motor_control) {
xQueueOverwrite(motor_control_queue, &new_motor_control);
// Wake up task
xTaskNotifyGive(i2c_comms_task_handle);
}
// Ask the I2C task to send a motor parameter packet
void set_motor_parameters(motor_parameters_group_t new_motor_parameters){
void set_motor_parameters(motor_parameters_group_t new_motor_parameters) {
xQueueOverwrite(motor_parameter_queue, &new_motor_parameters);
// Wake up task
xTaskNotifyGive(i2c_comms_task_handle);
}
#define TCAADDR 0x70
// Sends command to the TCA9548 I2C mux to connect a different pressure sensor. Returns value from Wire transmission.
uint8_t select_pipe_sensor(uint8_t i) {
if (i > 7)
return 1;
Wire.beginTransmission(TCAADDR);
Wire.write(1 << i);
return Wire.endTransmission();
}
static void i2c_comms_task(void *pvParameters) {
uint8_t reply_bytecount;
motor_status_packet_t i2c_reply;
motor_write_packet_t motor_write_packet;
pipe_pressure_status_t pipe_pressure_status;
// After power on, I2C mux has no bus selected
select_pipe_sensor(0);
// irritatingly, this includes a 10ms delay
mpr_sensor.begin();
for (;;) {
// Only need to run this task when there is something to do on the I2C bus
@ -71,10 +108,32 @@ static void i2c_comms_task(void *pvParameters) {
}
}
// TODO Get pipe pressure update
if (xSemaphoreTake(pipe_pressure_semaphore, 0) == pdTRUE) {
// Need to have short-circuit logic here on I2C errors, as otherwise we can easily wind up spending whole
// seconds with all of the transaction timeouts
bool valid_measurement = true;
for (int p_id = 0; p_id < 8; p_id++) {
if (select_pipe_sensor(p_id) != 0) {
valid_measurement = false;
break;
}
pipe_pressure_status.pipes[p_id] = mpr_sensor.readPressure();
if (pipe_pressure_status.pipes[p_id] == NAN) {
valid_measurement = false;
break;
}
}
if (valid_measurement) {
// Pass the pipe pressure status back to the main task
xQueueOverwrite(pipe_pressure_queue, &pipe_pressure_status);
}
}
// Send a motor control packet if requested
if (xQueueReceive(motor_control_queue, &motor_write_packet.control, 0)==pdTRUE){
if (xQueueReceive(motor_control_queue, &motor_write_packet.control, 0) == pdTRUE) {
motor_write_packet.packet_type = MOTOR_CONTROL_PACKET;
Wire.beginTransmission(MOTOR_ESP32_SLAVE_I2C_ADDR);
Wire.write((byte *)&motor_write_packet, sizeof(motor_write_packet));
@ -82,7 +141,7 @@ static void i2c_comms_task(void *pvParameters) {
}
// Send a motor parameter packet if requested
if (xQueueReceive(motor_parameter_queue, &motor_write_packet.params, 0)==pdTRUE){
if (xQueueReceive(motor_parameter_queue, &motor_write_packet.params, 0) == pdTRUE) {
motor_write_packet.packet_type = MOTOR_PARAMETERS_PACKET;
Wire.beginTransmission(MOTOR_ESP32_SLAVE_I2C_ADDR);
Wire.write((byte *)&motor_write_packet, sizeof(motor_write_packet));
@ -94,11 +153,15 @@ static void i2c_comms_task(void *pvParameters) {
void i2c_comms_setup(void) {
// Initialise the I2C master
Wire.begin(GPIO_I2C_SDA, GPIO_I2C_SCL, (uint32_t)I2C_FREQUENCY);
Wire.setTimeOut(10);
// Initialise our queues and semaphores
motor_status_semaphore = xSemaphoreCreateBinary();
motor_status_queue = xQueueCreate(1, sizeof(motor_status_packet_t));
pipe_pressure_semaphore = xSemaphoreCreateBinary();
pipe_pressure_queue = xQueueCreate(1, sizeof(pipe_pressure_status_t));
motor_control_queue = xQueueCreate(1, sizeof(motor_control_group_t));
motor_parameter_queue = xQueueCreate(1, sizeof(motor_parameters_group_t));

@ -3,11 +3,18 @@
#include "../common/shared_structs.h"
typedef struct {
float pipes[8];
} pipe_pressure_status_t;
void i2c_comms_setup(void);
bool get_motor_status_update(motor_status_packet_t *status_packet);
void request_motor_status_update();
bool get_pipe_pressure_status_update(pipe_pressure_status_t *status_update);
void request_pipe_pressure_update();
void set_motor_control(motor_control_group_t new_motor_control);
void set_motor_parameters(motor_parameters_group_t new_motor_parameters);

@ -13,10 +13,11 @@ that's been bundled out into its own FreeRTOS module (using the ESP IDF librarie
#include "io.h"
#include "wheel_speed.h"
#define MOTOR_STATUS_UPDATE_PERIOD_MS 500
#define WHEEL_STATUS_UPDATE_PERIOD_MS 1000
#define BIN_STATUS_UPDATE_PERIOD_MS 3000
#define HEARTBEAT_PERIOD_MS 1000
#define MOTOR_STATUS_UPDATE_PERIOD_MS 500
#define WHEEL_STATUS_UPDATE_PERIOD_MS 1000
#define BIN_STATUS_UPDATE_PERIOD_MS 3000
#define PIPE_PRESSURE_UPDATE_PERIOD_MS 2000
#define HEARTBEAT_PERIOD_MS 1000
// Rate at which the current wheel speed will be used to update the desired roller speed
#define MOTOR_CONTROL_PERIOD_MS 100
@ -178,12 +179,15 @@ void onConnectionEstablished() {
motor_status_packet_t motor_status;
pipe_pressure_status_t pipe_pressure_status;
motor_control_group_t motor_control_group;
unsigned long now = 0;
unsigned long last_motor_status = 0;
unsigned long last_wheel_status = 0;
unsigned long last_bin_status = 0;
unsigned long last_pipe_pressure_status = 0;
unsigned long last_heartbeat = 0;
unsigned long no_comms_timeout_start = 0;
@ -248,6 +252,21 @@ void loop() {
mqtt_client.publish("airseeder/status/roller3", msg_buffer, true);
}
// Periodically request a pipe pressure update via I2C
if (now - last_pipe_pressure_status > PIPE_PRESSURE_UPDATE_PERIOD_MS) {
last_pipe_pressure_status = now;
request_pipe_pressure_update();
}
// Publish the pipe pressure status update when it comes back
if (get_pipe_pressure_status_update(&pipe_pressure_status)) {
sprintf(msg_buffer, "%lu %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f", now, pipe_pressure_status.pipes[0],
pipe_pressure_status.pipes[1], pipe_pressure_status.pipes[2], pipe_pressure_status.pipes[3],
pipe_pressure_status.pipes[4], pipe_pressure_status.pipes[5], pipe_pressure_status.pipes[6],
pipe_pressure_status.pipes[7]);
mqtt_client.publish("airseeder/status/pipepressure", msg_buffer, true);
}
// Periodically publish the wheel status
if (now - last_wheel_status > WHEEL_STATUS_UPDATE_PERIOD_MS) {
last_wheel_status = now;

Loading…
Cancel
Save