mirror of
https://github.com/ArduPilot/ardupilot
synced 2025-01-03 06:28:27 -04:00
AP_WindVane: add Arduino script and readme to allow conection to Bluetooth wind-vane
This commit is contained in:
parent
a3812d7632
commit
34d2a5acaa
Binary file not shown.
After Width: | Height: | Size: 180 KiB |
@ -0,0 +1,214 @@
|
||||
#include <bluefruit.h>
|
||||
|
||||
// This code uses the bluefruit libary52 from Adafruit
|
||||
// Documentation here: https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/bluefruit-nrf52-api
|
||||
// Should work with any nrf52 Bluetooth Arduino, tested with Seeed XIAO nRF52840 Sense
|
||||
|
||||
// Wind vane address, found with mobile app
|
||||
#define WIND_VANE_ADDRESS 0xDDB7BEB45638
|
||||
|
||||
// Define services and charicteristics to moniter
|
||||
BLEClientService env_sense(0x181A); // Environmental Sensing
|
||||
BLEClientCharacteristic wind_speed(0x2A72); // Apparent Wind Speed
|
||||
BLEClientCharacteristic wind_dir(0x2A73); // Apparent Wind Direcetion
|
||||
|
||||
BLEClientService bat_sense(0x180F); // Battery Sensing
|
||||
BLEClientCharacteristic bat_level(0x2A19); // Battery level
|
||||
|
||||
ble_gap_addr_t addr;
|
||||
|
||||
float speed;
|
||||
float direction;
|
||||
uint8_t battery_level;
|
||||
|
||||
bool speed_new;
|
||||
bool direction_new;
|
||||
bool battery_new;
|
||||
|
||||
uint32_t last_connect_attempt;
|
||||
|
||||
#define RECONNECT_TIME_MS 1000
|
||||
#define NMEA_BAUD 57600
|
||||
#define LOW_BAT_BLINK_MS 200
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Disconected
|
||||
digitalWrite(LED_RED, LOW);
|
||||
|
||||
uint64_t address = WIND_VANE_ADDRESS;
|
||||
memcpy(addr.addr, &address, BLE_GAP_ADDR_LEN);
|
||||
|
||||
addr.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC;
|
||||
|
||||
// Extra info and debugging on USB, NMEA on serial 1
|
||||
Serial.begin(115200);
|
||||
Serial1.begin(NMEA_BAUD);
|
||||
|
||||
Serial.println("ArduPilot Bluetooth windvane to NMEA translator");
|
||||
|
||||
Bluefruit.begin(0, 1);
|
||||
Bluefruit.setName("ArduPilot Bluetooth");
|
||||
|
||||
// Initialize services client
|
||||
env_sense.begin();
|
||||
bat_sense.begin();
|
||||
|
||||
// Set notify callbacks
|
||||
wind_speed.setNotifyCallback(speed_notify_callback);
|
||||
wind_dir.setNotifyCallback(direction_notify_callback);
|
||||
bat_level.setNotifyCallback(bat_notify_callback);
|
||||
|
||||
// Initalize Caricterstics
|
||||
wind_speed.begin(&env_sense);
|
||||
wind_dir.begin(&env_sense);
|
||||
bat_level.begin(&bat_sense);
|
||||
|
||||
// Turn of LEDs, we do our own
|
||||
Bluefruit.autoConnLed(false);
|
||||
|
||||
// Callbacks for Central
|
||||
Bluefruit.Central.setDisconnectCallback(disconnect_callback);
|
||||
Bluefruit.Central.setConnectCallback(connect_callback);
|
||||
|
||||
// Connect to known address
|
||||
Bluefruit.Central.connect(&addr);
|
||||
last_connect_attempt = millis();
|
||||
}
|
||||
|
||||
bool low_battery;
|
||||
uint32_t last_low_battery_blink;
|
||||
char NMEA_buffer[50];
|
||||
void loop()
|
||||
{
|
||||
if (!Bluefruit.connected(0)) {
|
||||
// Disconected
|
||||
digitalWrite(LED_RED, LOW);
|
||||
digitalWrite(LED_GREEN, HIGH);
|
||||
|
||||
const uint32_t now = millis();
|
||||
if (now - last_connect_attempt > RECONNECT_TIME_MS) {
|
||||
// try and re-connect
|
||||
Bluefruit.Central.connect(&addr);
|
||||
last_connect_attempt = now;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Connected, show green LED
|
||||
digitalWrite(LED_GREEN, LOW);
|
||||
|
||||
// flash red LED for low battery
|
||||
if (low_battery) {
|
||||
const uint32_t now = millis();
|
||||
if (now - last_low_battery_blink > LOW_BAT_BLINK_MS) {
|
||||
digitalWrite(LED_RED, !digitalRead(LED_RED));
|
||||
last_low_battery_blink = now;
|
||||
}
|
||||
} else {
|
||||
digitalWrite(LED_RED, HIGH);
|
||||
}
|
||||
|
||||
if (speed_new && direction_new) {
|
||||
speed_new = false;
|
||||
direction_new = false;
|
||||
|
||||
Serial.printf("Wind Speed: %0.2f (m/s), Direction: %0.2f (deg), Battery: %u%%\n", speed, direction, battery_level);
|
||||
|
||||
sprintf(NMEA_buffer, "APMWV,%0.2f,R,%0.2f,M,A", direction, speed);
|
||||
Serial1.printf("$%s*%02X\n",NMEA_buffer, NMEA_checksum(NMEA_buffer));
|
||||
}
|
||||
|
||||
if (battery_new) {
|
||||
battery_new = false;
|
||||
|
||||
sprintf(NMEA_buffer, "APXDR,G,%u,%%,BT", battery_level);
|
||||
Serial1.printf("$%s*%02X\n",NMEA_buffer, NMEA_checksum(NMEA_buffer));
|
||||
|
||||
if (battery_level < 25) {
|
||||
// Windvane enters low power mode at less than 20% battery
|
||||
low_battery = true;
|
||||
} else if (battery_level > 30) {
|
||||
low_battery = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint8_t NMEA_checksum(const char* NMEA_string)
|
||||
{
|
||||
uint8_t checksum = 0;
|
||||
for (uint8_t i = 0; i < strlen(NMEA_string); i++) {
|
||||
checksum ^= NMEA_string[i];
|
||||
}
|
||||
return checksum;
|
||||
}
|
||||
|
||||
void connect_callback(uint16_t conn_handle)
|
||||
{
|
||||
Serial.println("Connected");
|
||||
|
||||
Serial.print("Discovering Environmental characteristics ... ");
|
||||
if (!env_sense.discover(conn_handle) || !wind_speed.discover() || !wind_dir.discover()) {
|
||||
Serial.println("Failed");
|
||||
Bluefruit.disconnect(conn_handle);
|
||||
return;
|
||||
}
|
||||
Serial.println("Found");
|
||||
|
||||
|
||||
Serial.print("Discovering Battery characteristics ... ");
|
||||
if (!bat_sense.discover(conn_handle) || !bat_level.discover()) {
|
||||
Serial.println("failed");
|
||||
Bluefruit.disconnect(conn_handle);
|
||||
return;
|
||||
}
|
||||
Serial.println("Found");
|
||||
|
||||
if (wind_speed.enableNotify() && wind_dir.enableNotify() && bat_level.enableNotify()) {
|
||||
Serial.println("Ready to receive");
|
||||
} else {
|
||||
Serial.println("Couldn't enable notify. Increase DEBUG LEVEL for troubleshooting");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
|
||||
{
|
||||
(void) conn_handle;
|
||||
|
||||
speed_new = false;
|
||||
direction_new = false;
|
||||
battery_new = false;
|
||||
|
||||
Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
|
||||
}
|
||||
|
||||
|
||||
void speed_notify_callback(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len)
|
||||
{
|
||||
if (len == 2) {
|
||||
uint16_t value;
|
||||
memcpy(&value, data, 2);
|
||||
speed = value * 0.01;
|
||||
speed_new = true;
|
||||
}
|
||||
}
|
||||
|
||||
void direction_notify_callback(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len)
|
||||
{
|
||||
if (len == 2) {
|
||||
uint16_t value;
|
||||
memcpy(&value, data, 2);
|
||||
direction = value * 0.01;
|
||||
direction_new = true;
|
||||
}
|
||||
}
|
||||
|
||||
void bat_notify_callback(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len)
|
||||
{
|
||||
if (len == 1) {
|
||||
battery_level = data[0];
|
||||
battery_new = true;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
# Bluetooth to NMEA receiver
|
||||
|
||||
This script can be used with a Arduino compatible nRF52 Bluetooth module to receive wind readings from a CALYPSO Ultrasonic Portable Mini wind meter and output NMEA 0183 for use with ArduPilot. Such a sensor is smaller and lighter than typical sensors and removes the need to run cabling to the top of the mast.
|
||||
|
||||
## Hardware setup
|
||||
|
||||
Any Arduino compatible nRF52 Bluetooth board should work, this guide is written for a Seeed XIAO nRF52840 Sense. Three connections need to be made between the flight controller and XIAO. The image below shows the connections from both the top and bottom of the XIAO. 5v (Red), ground (black) and TX (green) to a serial port RX pin on the flight controller.
|
||||
|
||||
![XIAO connections](XIAO_connection_diagram.png)
|
||||
|
||||
## Script setup
|
||||
|
||||
Follow the instructions from the manufacturer to setup the Arduino envoroment for your board. Install the [Adafruit nRF52](https://github.com/adafruit/Adafruit_nRF52_Arduino/tree/master/libraries/Bluefruit52Lib) library as outlined here: https://github.com/adafruit/Adafruit_nRF52_Arduino#bsp-installation.
|
||||
|
||||
Use a smartphone and blue tooth tool to find the adress of your windvane. On Android [BLE Scanner](https://play.google.com/store/apps/details?id=com.macdom.ble.blescanner&hl=en_GB&gl=US) can be used, although there are many equivalent apps.
|
||||
|
||||
Locate the wind-vane and note down its address, in this case `DD:B7:BE:B4:56:38`.
|
||||
|
||||
![Wind-vane address](BLE_Scanner.jpg)
|
||||
|
||||
Take your the address and replace the one at the top of the script, removing colons and pre-fixing `0x` to denote a hexadecimal value. For example:
|
||||
```
|
||||
#define WIND_VANE_ADDRESS 0xDDB7BEB45638
|
||||
```
|
||||
|
||||
Save the script and flash it to your nRF52 board. The LED will be red if no connection can be made it will go green once a connection has been established, this can take a few seconds. If the green LED is solid and the red LED flashing it is connected but the wind-vane has less than 25% battery remaining, it will go into low power mode once it reaches 20%.
|
||||
|
||||
Note! The wind-vane can only accept one connection at a time, if you cann't connect make sure nothing else is connected to the wind-vane.
|
||||
|
||||
## ArduPilot setup
|
||||
|
||||
The Arduino script is setup to output NMEA 0183 messages as they are already supported by ArduPilot.
|
||||
|
||||
Enable NMEA wind-vane with:
|
||||
```
|
||||
WNDVN_TYPE 4
|
||||
WNDVN_SPEED_TYPE 4
|
||||
```
|
||||
Setup the serial port you have connected the nRF52 to with:
|
||||
```
|
||||
SERIALx_PROTOCOL 21
|
||||
SERIALx_BAUD 57
|
||||
```
|
||||
|
||||
After a re-boot you should see wind messages reported to the GCS. For example `MAV_APPWNDDIR` and `MAV_APPWNDSPD` can be selected in mission planner to display the apparent wind direction and speed.
|
||||
|
||||
![Mission Planner wind speed and direction](Mission_Planner_Quick.PNG)
|
||||
|
||||
## Future work
|
||||
|
||||
The script does send back the battery level of the wind-vane formatted as a NMEA `XDR` message. Some ArduPilot changes are required to allow this value to be parsed and displayed.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 MiB |
Loading…
Reference in New Issue
Block a user