|
|
tbd |
|
|
\ No newline at end of file |
|
|
[[_TOC_]]
|
|
|
|
|
|
# Project Background
|
|
|
This project is meant to be an extension of the previous
|
|
|
[Altimeter project](./2023-Altimeter.md) which was built to measure the maximum
|
|
|
height reached by a model rocket. This version of the altimeter is built on
|
|
|
a different platform and utilizes different and more sensors to collect data
|
|
|
during the ascent of the rocket. The display from the original project is gone and
|
|
|
replaced with a webinterface which can be accessed over a WiFi connection.
|
|
|
|
|
|
# Usage
|
|
|
## WiFi Credential setup
|
|
|
One set of WiFi credentials can be embedded into the firmware during flashing.
|
|
|
On startup, the microcontroller will attempt to connect to the WiFi network
|
|
|
provided by those credentials and if that fails will open its own network.
|
|
|
|
|
|
The file containing the credentials should be named `wifi_credentials.h` and
|
|
|
be located in the `src` folder. It will automatically be excluded from
|
|
|
version control to avoid leaking of credentials.
|
|
|
|
|
|
The contents of the file should look like the following
|
|
|
```C++
|
|
|
#ifndef WIFI_CREDENTIALS_H
|
|
|
#define WIFI_CREDENTIALS_H
|
|
|
#define WIFI_SSID "YourWiFiSSID"
|
|
|
#define WIFI_PASSWORD "YourWiFiPassword"
|
|
|
#endif // WIFI_CREDENTIALS_H
|
|
|
```
|
|
|
|
|
|
## Starting/Stopping measurements
|
|
|
Before starting the sampling process, ensure that the measured reference values
|
|
|
are sensible by checking the webinterface, as the height calculation is relative
|
|
|
to those values. If they do not make sense, a recalibration can be triggered
|
|
|
from the webinterface.
|
|
|
|
|
|
The sampling process can be started by pressing the user button
|
|
|
connected to pin D8 on the controller or by using the start button in the
|
|
|
webinterface.
|
|
|
|
|
|
When the statemachine is in the sampling state, pressing the user button or
|
|
|
the start button in the webinterface again will restart the measurements and
|
|
|
discard existing samples.
|
|
|
|
|
|
The sampling process stops either when the current measured height falls a
|
|
|
configurable distance below the maximum height or when the stop button in the
|
|
|
webinterface is pressed. Afterwards the statemachine enters the idle stop state
|
|
|
and can be restarted by pressing the start buttons again. This will however
|
|
|
discard the previous measurement results.
|
|
|
|
|
|
## Downloading results
|
|
|
The measured sensor values and the reference measurements on ground level which
|
|
|
are established during startup can be downloaded in csv format using the
|
|
|
corresponding buttons in the webinterface.
|
|
|
|
|
|
Measurement results stay available, even after a reboot, until the measurement
|
|
|
process is started again.
|
|
|
|
|
|
## Visualization
|
|
|
A python script has been provided in the folder `plotter` which can use the
|
|
|
downloaded samples and reference values to plot a height over time graph.
|
|
|
|
|
|
# Technical information
|
|
|
## Hardware used
|
|
|
The microcontroller used is the Seeed Studio XIAO ESP32C3. The sensor board
|
|
|
is called GY-86 and is comprised of 3 different sensors which can all be
|
|
|
accessed over I2C.
|
|
|
| Name | Description | I2C address |
|
|
|
| -------- | ----------------------------------------- | ----------- |
|
|
|
| HMC5883L | 3-Axis digital compass | 0x3C |
|
|
|
| MPU-6050 | 3-axis gyroscope and 3-axis accelerometer | 0x68 |
|
|
|
| MS5611 | Altimeter | 0x77 |
|
|
|
|
|
|
## Libraries used
|
|
|
- [Adafruit HMC5883L Driver (3-Axis Magnetometer)](https://github.com/adafruit/Adafruit_HMC5883_Unified)
|
|
|
- [Adafruit MPU6050](https://github.com/adafruit/Adafruit_MPU6050)
|
|
|
- [MS5611](https://github.com/RobTillaart/MS5611)
|
|
|
- [ESPAsyncWebServer](https://github.com/esphome/ESPAsyncWebServer)
|
|
|
- [ArduinoJson](https://github.com/bblanchon/ArduinoJson)
|
|
|
|
|
|
## Wiring
|
|
|
**ESP32 to sensor:**
|
|
|
| XIAO ESO32C3 | GY-86 |
|
|
|
| ------------ | ------ |
|
|
|
| NC | VCC_IN |
|
|
|
| 3V3 | 3.3V |
|
|
|
| GND | GND |
|
|
|
| D5 | SCL |
|
|
|
| D4 | SDA |
|
|
|
| NC | FSYNC |
|
|
|
| NC | INTA |
|
|
|
| NC | DRDY |
|
|
|
|
|
|
An additional user button was added connecting pin D8 directly to the 3.3V pin.
|
|
|
This button is used as the main user button in the program and is also relevant
|
|
|
for correctly entering debug mode with this board.
|
|
|
|
|
|
## Debugging
|
|
|
<b style="color: red;"> The ESP32 can only be powered from the 5V pin or USB.
|
|
|
The GY-86 requires 3V3 volt though so don't use the same supply for both.
|
|
|
Also [do not connect the battery without a diode](https://wiki.seeedstudio.com/XIAO_ESP32C3_Getting_Started/#power-pins)
|
|
|
while powering the ESP32 from the 5V pin.</b>
|
|
|
|
|
|
The ESP32C3 has a builtin debugger.
|
|
|
To allow gdb debug connection to succeed, D8 has to be pulled to 3.3V during boot.
|
|
|
Otherwise a `Failed to get flash maps` error will be triggered.
|
|
|
|
|
|
See also the [additional resources](#additional-resourcesguides) for information
|
|
|
on setting up the debugger and utilizing it.
|
|
|
|
|
|
## FreeRTOS tasks
|
|
|
### Main task (Statemachine task)
|
|
|
This task is responsible for running the altimeter statemachine.
|
|
|
It is implemented in the main function.
|
|
|
|
|
|
### Sensor task
|
|
|
The backbone of the system. This task is responsible for sampling the
|
|
|
sensors in a fixed interval and sending the data to the statemachine task
|
|
|
using a FreeRTOS queue. If the statemachine is not in the measuring state,
|
|
|
this task is suspended.
|
|
|
|
|
|
### Clock task
|
|
|
The simplest task is that of the clock task, which will in regular intervals
|
|
|
increment the system clock to keep track of time in a simple human readable
|
|
|
format.
|
|
|
|
|
|
### Webserver
|
|
|
The AsyncWebserver library implements its own tasks to asynchronously handle webserver requests.
|
|
|
|
|
|
## Statemachine
|
|
|

|
|
|
|
|
|
The statemachine is implemented using transition tables to keep track of
|
|
|
which event triggers which transition and what action to take during
|
|
|
that transition.
|
|
|
|
|
|
There are 2 kinds of transition tables used for this.
|
|
|
- **Inner transition table:** Each state has exactly one inner transition table.
|
|
|
Each entry in this table defines the event triggering an outgoing transition,
|
|
|
the target state of the transition, an optional transition guard and an
|
|
|
optional transition action.
|
|
|
- **Outer transition table:** This transition table assigns the definitions of
|
|
|
inner transition tables to their corresponding statemachine states.
|
|
|
|
|
|
The `processEvent()` function checks a new event and finds whether the current
|
|
|
state has a corresponding transition which is not currently blocked by a
|
|
|
transition guard. If a valid transition is found, the optional transition action
|
|
|
is executed and the statemachine transitions into the new state.
|
|
|
|
|
|
### st_Initialization
|
|
|
The default state upon starting the controller. This state will take some reference measurements to determine the relative height of later measurements.
|
|
|
|
|
|
### st_Measuring
|
|
|
The main state of the statemachine. While in this state,
|
|
|
sensor data will be pulled in as provided by the sensor task and stored in
|
|
|
the global `dataStore` object.
|
|
|
Additionally the current height will be calculated and checked against the
|
|
|
maximum measured height to be able to trigger the `ev_Falling` event.
|
|
|
|
|
|
When transitioning to the stopped state, the measured sensor values
|
|
|
will be stored to a file in flash to save them in case of a reboot.
|
|
|
|
|
|
### st_StoppedMeasuring
|
|
|
Idle state. Allows restarting (and thereby overwriting!!!) the measurements.
|
|
|
|
|
|
## Component diagram
|
|
|

|
|
|
|
|
|
## Filesystem
|
|
|
Note: LittleFS requires absolute paths (filenames must start with a `/`).
|
|
|
It also cannot use files which are stored in folders other than the current one.
|
|
|
|
|
|
The filesystem is implemented using a self-written abstraction layer to
|
|
|
allow testing of certain components in a desktop environment.
|
|
|
On a desktop machine standard C++ library functions are used for file accesses.
|
|
|
On the microcontroller LittleFS is used instead.
|
|
|
LittleFS is used to persist a single measurement run in flash.
|
|
|
The saving is done automatically at the end of the measurement cycle.
|
|
|
|
|
|
## REST API
|
|
|
All API requests have to be directed to various subdirectories of the `/api` path depending
|
|
|
on their intended purpose.
|
|
|
|
|
|
### `/api/sensors`
|
|
|
|
|
|
**HTTP GET Requests:**
|
|
|
| Parameters | Expected response | Example request |
|
|
|
| ---------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------- |
|
|
|
| None (always returned) | Returns current sensor values. These are not read from the buffer but instead freshly requested from the sensors. | `<url>/api/sensors` |
|
|
|
| `references` | Returns the current references and offsets values used for calibrating the sensor measurements | `<url>/api/sensors?references` |
|
|
|
|
|
|
This endpoint allows chaining of multiple parameters listed in the table. For example, sending a request `<url>/api/sensors?sampleCount&references`
|
|
|
will return the data from both of those parameters and a current sensor value. Adding the `from=` and `to=` parameters to this request,
|
|
|
will return a chunk of measured sensor values instead of a current sensor value.
|
|
|
|
|
|
### `/api/log`
|
|
|
|
|
|
**HTTP GET Requests:**
|
|
|
| Parameters | Expected response | Example request |
|
|
|
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
|
|
|
| None | Returns last log message | `<url>/api/log` |
|
|
|
| `from=`, `to=` | Returns chunk of log messages. Can be negative or positive indexed, e.g. `from=-1` and `to=-3` will return the 3 newest messages while `from=0` and `to=2` will return the 3 oldest. Requesting more messages than exist will not cause an error and only return the maximum currently available. | `<url>/api/log?from=-1&to=-3` |
|
|
|
|
|
|
### `/api/system`
|
|
|
|
|
|
**HTTP GET Requests:**
|
|
|
| Parameters | Expected response | Example request |
|
|
|
| ------------- | -------------------------------------------------------------- | ------------------------------ |
|
|
|
| None | Returns general system information such as current system time | `<url>/api/system` |
|
|
|
| `clock-state` | Returns the state of the system clock | `<url>/api/system?clock-state` |
|
|
|
|
|
|
**HTTP POST:**
|
|
|
| Parameters | Result |
|
|
|
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
| `h=`, `m=`, `s=` | Sets the hours, minutes and seconds of the controllers internal clock. Parameters must all be used and must be in valid range or HTTP 400 will be returned. |
|
|
|
| `restart=true` | Restarts the controller. |
|
|
|
| `rezero=true` | Recalibrates the reference temperature and pressure for the relative height calculation |
|
|
|
| `start=true` | Triggers start event for state machine. Response of controller depends on current state. Cannot be sent along with `stop=true`. |
|
|
|
| `stop=true` | Triggers stop event for state machine. Response of controller depends on current state. Cannot be sent along with `start=true`. |
|
|
|
|
|
|
### `/api/file`
|
|
|
|
|
|
**HTTP GET Requests:**
|
|
|
| Parameters | Expected response | Example request |
|
|
|
| ------------ | ------------------------------------------------------------------------------------------------------ | ------------------------------------ |
|
|
|
| `filename=` | Tries to open a file with the given filename and returns it on success. Filename must start with a `/` | `<url>/api/file?filename=/style.css` |
|
|
|
| `data` | Returns the file storing the persisted measurement data from the previous measurement run. | `<url>/api/file?data` |
|
|
|
| `references` | Returns the file storing the reference measurements | `<url>/api/file?references` |
|
|
|
|
|
|
## Unit tests
|
|
|
|
|
|
## Known Issues
|
|
|
- **Sensor task dropping samples while old values are written to filesystem:**<br>
|
|
|
The sensor task often drops individual values due to missed deadlines when the
|
|
|
statemachine task is busy writing old sensor values to the filesystem.
|
|
|
This is likely caused by the filesystem operations taking too long.
|
|
|
Theoretically the sensor task should not be impacted by this as it is
|
|
|
explicitly executed on another processor core and has a higher priority than
|
|
|
any other task.
|
|
|
- **wifiScan function prevents webinterface log messages:**<br>
|
|
|
The `wifiScan()` function (defined in `main.cpp`) can prevent the webinterface from displaying log messages when used.
|
|
|
This is caused by the function finding networks with non-ASCII symbols in their name, printing them to the log and the
|
|
|
JSON parser in the webinterface failing to interpret those characters.
|
|
|
- **WiFi SoftAP signal extremely weak:**<br>
|
|
|
The WiFi network hosted by the controller when no other network can be connected to
|
|
|
is extremely short range and often drops the connection to client devices.
|
|
|
- **HMC5883 sensor does not work at all:**<br>
|
|
|
When using the HMC5883 sensor (compass), only `[Wire.cpp:499] requestFrom(): i2cWriteReadNonStop returned Error -1`
|
|
|
is logged to the UART. This is likely a driver issue. For the time being requests to this sensor have been
|
|
|
completely disabled in the `getSensorValues()` function in `sensors.cpp`.
|
|
|
- **[ 20758][E][vfs_api.cpp:105] open(): /littlefs/persistData.csv does not exist, no permits for creation:**<br>
|
|
|
This error indicates the LittleFS library is trying to open a file that does
|
|
|
not exist. To check whether a file exists with LittleFS, the program has to
|
|
|
try and open it. If the open command fails, the file does not exist.
|
|
|
This error is caused by the webserver periodically checking whether a file
|
|
|
containing data to download is available, to indicate this state to the user.
|
|
|
Once a file has been created due to the program entering the sampling state,
|
|
|
it goes away.
|
|
|
|
|
|
# Future Improvements
|
|
|
## Hardware improvement ideas:
|
|
|
- Onboard SMD LED for simple status indication
|
|
|
- Onboard switch for correctly entering debug mode
|
|
|
|
|
|
## Software improvement ideas:
|
|
|
- Fix the [known issues](#known-issues)
|
|
|
- Expand plotting script to perform post processing of data before plotting,
|
|
|
such as filtering out measurement spikes.
|
|
|
- Expand plotting script to also plot the flight path. This requires measuring
|
|
|
the orientation of the controller during flight though for which the HMC5883
|
|
|
sensor issue has to be resolved.
|
|
|
- Improve webinterface design
|
|
|
|
|
|
|
|
|
# Additional resources/guides
|
|
|
## General information
|
|
|
- [Getting Started with Seeed Studio XIAO ESP32C3](https://wiki.seeedstudio.com/XIAO_ESP32C3_Getting_Started/): Getting started guide for MCU. Includes pinout and general information.
|
|
|
- [Seeed Studio XIAO ESP32C3](https://docs.platformio.org/en/latest/boards/espressif32/seeed_xiao_esp32c3.html): PlatformIO docs for using the XIAO ESP32C3.
|
|
|
- [First Steps with a GY-86 10DOF Sensor: MPU6050, HMC5883L and MS5611](https://www.youtube.com/watch?v=hvjNaIlHPV0): Getting started YouTube video.
|
|
|
|
|
|
## Debugging
|
|
|
- [Debug an ESP32-C3 via its JTAG interface](https://tutoduino.fr/en/tutorials/debug-esp32/debug-an-esp32-c3-via-its-jtag-interface/): Setup of JTAG debugging using on-board JTAG interface.
|
|
|
- [JTAG Debugging Tips and Quirks](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-guides/jtag-debugging/tips-and-quirks.html): Tips and quirks for jtag debugging on an ESP32.
|
|
|
- [Use the PlatformIO Debugger on the ESP32 Using an ESP-prog](https://www.hackster.io/brian-lough/use-the-platformio-debugger-on-the-esp32-using-an-esp-prog-f633b6): Guide to using the esp-prog debug probe in PlatformIO.
|
|
|
- [ESP32 Web Server using Server-Sent Events (Update Sensor Readings Automatically)](https://randomnerdtutorials.com/esp32-web-server-sent-events-sse/): Example on how to automatically update information on a webpage from the controller side. |
|
|
\ No newline at end of file |