I did buy some Bno imus. I may need some help setting everything up, thanks for all the advice everyone.
for an excavator could i put imus on the machine and daisy chain all via Qwiic/i2c to an esp32 that is also connect to a f9p by i2c and the esp fuses the data for opengrade? and include all the math in the code? would agopengps be better for this with all its imu features? sorry for all the questions i have a lot to learn
SparkFun Thing Plus - ESP32-C6 connected to a bno085 via i2c connected to a f9p via i2c
Maybe I should look more into teensy v4.2 that could be better and easier for what I’m trying to do.
I think I should be able to use these devices to fuse the data together to create a panda message for agopengps or opengrade
To test I think I should put my antenna on a pole and put the imu on the pole and see if it detects the tilt
I dont know how i would calibrate the bno and f9p to a pole or a machine. Maybe you put all the offsets in the code.
code I’ve been testing
#include <Wire.h>
#include <SparkFun_u-blox_GNSS_Arduino_Library.h>
#include “BNO08x_AOG.h” // Using the BNO08x_AOG library
// Constants and settings
const byte BNO08x_I2C_ADDRESS = 0x4A; // Default I2C address of the BNO08x
// Variables for IMU and GPS
BNO080 bno08x;
SFE_UBLOX_GNSS myGNSS;
float roll = 0, heading = 0, pitch = 0;
float latitude = 0.0;
float longitude = 0.0;
float altitude = 0.0;
int satellites = 0;
int fix_type = 0;
float hdop = 0.0;
String timeStamp = “000000.00”; // Placeholder for time
void setup() {
Serial.begin(115200); // Initialize Serial at 115200 baud
delay(100); // Allow time for Serial to start
Wire.begin(); // Initialize I2C communication
// Start the BNO080 with the specified I2C address
if (!bno08x.begin(BNO08x_I2C_ADDRESS, Wire)) {
Serial.println("BNO08x not detected. Check wiring or I2C address.");
while (1); // Halt execution if IMU is not detected
} else {
Serial.println("BNO08x detected successfully.");
}
// Configure BNO080 for rotation vector (yaw, pitch, roll)
bno08x.enableRotationVector(25); // Set update rate to 40 Hz (or adjust as needed)
// Start the F9P (u-blox GNSS module)
if (!myGNSS.begin()) {
Serial.println("F9P not detected. Check wiring or I2C address.");
while (1); // Halt execution if GNSS is not detected
} else {
Serial.println("F9P detected successfully.");
myGNSS.setI2COutput(COM_TYPE_NMEA); // Ensure NMEA sentences are output over I2C
myGNSS.saveConfiguration(); // Save the current configuration
}
}
void loop() {
// Get IMU data if available
if (bno08x.dataAvailable()) {
heading = -bno08x.getYaw() * 180.0 / PI;
roll = bno08x.getRoll() * 180.0 / PI;
pitch = bno08x.getPitch() * 180.0 / PI;
if (heading < 0) heading += 360; // Adjust heading to 0-360 degrees
}
// Get GPS data if available
if (myGNSS.getPVT()) { // If a new PVT (position/velocity/time) data is available
latitude = myGNSS.getLatitude() / 10000000.0; // Convert to decimal degrees
longitude = myGNSS.getLongitude() / 10000000.0; // Convert to decimal degrees
altitude = myGNSS.getAltitude() / 1000.0; // Convert to meters
satellites = myGNSS.getSIV(); // Satellites in view
fix_type = myGNSS.getFixType(); // Fix type (e.g., 3D fix)
hdop = myGNSS.getHorizontalDOP() / 100.0; // Horizontal Dilution of Precision
timeStamp = myGNSS.getTimeOfWeek(); // GPS time of week (optional)
}
// Build PANDA sentence
String pandaSentence = "$PANDA," + timeStamp + ",";
pandaSentence += String(latitude, 7) + ",N,";
pandaSentence += String(longitude, 7) + ",W,";
pandaSentence += String(fix_type) + ",";
pandaSentence += String(satellites) + ",";
pandaSentence += String(hdop, 2) + ",";
pandaSentence += String(altitude, 2) + ",,,";
pandaSentence += "276.6,"; // Placeholder Course Over Ground (COG)
pandaSentence += String(heading, 2) + ",";
pandaSentence += String(pitch, 2) + ",";
pandaSentence += String(roll, 2) + "*";
// Calculate PANDA checksum
int pandaChecksum = 0;
for (int i = 1; i < pandaSentence.length() - 1; i++) {
pandaChecksum ^= pandaSentence[i];
}
pandaSentence += String(pandaChecksum, HEX);
// Build GGA sentence
String ggaSentence = "$GPGGA," + timeStamp + ",";
ggaSentence += String(latitude, 7) + ",N,";
ggaSentence += String(longitude, 7) + ",W,";
ggaSentence += String(fix_type) + ",";
ggaSentence += String(satellites) + ",";
ggaSentence += String(hdop, 2) + ",";
ggaSentence += String(altitude, 2) + ",M,,,";
// Calculate GGA checksum
int ggaChecksum = 0;
for (int i = 1; i < ggaSentence.length() - 1; i++) {
ggaChecksum ^= ggaSentence[i];
}
ggaSentence += "*" + String(ggaChecksum, HEX);
// Output both sentences
Serial.println(pandaSentence);
Serial.println(ggaSentence);
delay(250); // Adjust delay to control update rate
}
Just thinking about hardware… I bet a wheel angle sensor on every join would be the most stable.
If OG was setup for dual antenna it would be easier to get a heading of which way the offset was going….
I think it would require going deep into the source code in VS code editor but I’m lost in there.
I wonder if I guy would study how roll compensation is done and inject an offset from that is sent to teensy by serial from an Arduino calculating the three “WAS” sensors right there.
your not wrong WAS would be better and easier but i do want to try to learn more about imus. i want to add tilt compensation to a survey pole to learn how to fuse the gps and imu data together
here is some code ive been testing
code
#include <WiFi.h>
#include <WiFiClient.h>
#include <Wire.h>
#include “BNO08x_AOG.h” // Use the BNO08x_AOG library you confirmed works
#include “base64.h”
const char *ssid = “”;
const char *password = “”;
const char *ntripCaster = “”;
const uint16_t ntripPort = 2101;
const char *mountPoint = “”;
const char *username = “”;
const char *ntripPassword = “”;
// Adjust to your F9P’s I2C address
const int f9pAddress = 0x42; // Common default for F9P, but verify this for your setup
WiFiClient ntripClient;
BNO080 bno; // Create an instance of the BNO080 IMU
int bnoAddress = 0x4A; // Adjust if needed
// Calibration offsets (initialize to zero, update based on calibration)
float rollOffset = 0.0, pitchOffset = 0.0;
void setup() {
Serial.begin(115200); // For debug output
Wire.begin(); // Initialize I2C for F9P and BNO080
// Initialize BNO080 IMU
if (!bno.begin(bnoAddress, Wire)) {
Serial.println(“BNO08x not detected. Check wiring.”);
while (1); // Stop if IMU is not detected
}
bno.enableRotationVector(100); // Set IMU update rate to 10Hz
// Connect to Wi-Fi
Serial.print(“Connecting to WiFi…”);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(“.”);
}
Serial.println(“\nConnected to WiFi”);
// Connect to NTRIP caster
Serial.print(“Connecting to NTRIP caster…”);
if (!ntripClient.connect(ntripCaster, ntripPort)) {
Serial.println(“Failed to connect to NTRIP caster”);
while (true);
}
Serial.println(“Connected to NTRIP caster”);
// Send NTRIP request with Basic Authentication
String auth = base64::encode(String(username) + “:” + String(ntripPassword));
String ntripRequest = “GET /” + String(mountPoint) + " HTTP/1.0\r\n";
ntripRequest += "Authorization: Basic " + auth + “\r\n”;
ntripRequest += “User-Agent: NTRIP ESP32Client\r\n”;
ntripRequest += “Connection: close\r\n”;
ntripRequest += “\r\n”;
ntripClient.print(ntripRequest);
Serial.println(“Sent NTRIP request”);
// Check response from caster
while (ntripClient.available() == 0) {
delay(500);
Serial.print(“.”);
}
Serial.println(“\nNTRIP caster connection established”);
}
void loop() {
// Buffer to store incoming RTCM data for I2C transmission
uint8_t rtcmBuffer[32]; // Adjust buffer size if needed
int bufferIndex = 0;
// Read RTCM data from NTRIP and forward it to F9P over I2C
while (ntripClient.available()) {
rtcmBuffer[bufferIndex++] = ntripClient.read();
// If the buffer is full or the client has no more data to read, send it over I2C
if (bufferIndex >= sizeof(rtcmBuffer) || ntripClient.available() == 0) {
Wire.beginTransmission(f9pAddress);
for (int i = 0; i < bufferIndex; i++) {
Wire.write(rtcmBuffer[i]);
}
Wire.endTransmission();
bufferIndex = 0; // Reset the buffer index
}
}
// Read and display NMEA data from the F9P over I2C
readAndPrintNMEA();
// Fetch IMU data
if (bno.dataAvailable()) {
float roll = bno.getRoll() * 180.0 / PI - rollOffset;
float pitch = bno.getPitch() * 180.0 / PI - pitchOffset;
float heading = bno.getYaw() * 180.0 / PI;
// Create the PANDA sentence with IMU and NMEA data
Serial.print("$PANDA,");
Serial.print(roll, 2); // Two decimal places for roll
Serial.print(",");
Serial.print(pitch, 2); // Two decimal places for pitch
Serial.print(",");
Serial.print(heading, 2); // Two decimal places for heading
Serial.print("*CS"); // Replace with actual checksum if needed
Serial.println();
}
// Optionally, check if the connection was dropped and reconnect if necessary
if (!ntripClient.connected()) {
Serial.println(“Reconnecting to NTRIP caster…”);
ntripClient.stop();
setup(); // Retry connection by re-running setup
}
}
// Function to read and print NMEA data from the F9P over I2C
void readAndPrintNMEA() {
Wire.requestFrom(f9pAddress, 32); // Request 32 bytes from F9P (adjust if needed)
// Only read if there are available bytes
while (Wire.available()) {
char c = Wire.read();
Serial.print(c); // Print each character to the Serial Monitor
}
}
An alternative to a WAS could be a draw wire sensor on the rams.
Machine control is something that I’ve been thinking about for a while but haven’t yet had time to do anything about it. However, when I was last pondering it I came across this work that analysed the difference between IMUs and draw wire sensors.
It is quite a good read - gives an overview of calculations and how they mounted the sensors to test the them, but the conclusion is basically that the draw-wire sensor is much better.
i’ve been busy so i havent really had the chance to learn or try the code for my esp32 f9p bno till now. i need to modify the code a bit for it to work with ic2 and have it output the right nmea sentences for agopen. i feel like i could put f9p and ect on a pole connected to the bucket and it will tell me height and tilt, i’m not sure about heading or the right direction.
I just put the antenna on the bucket of my excavator. It does a good enough job for visual reference.
Sure it would be nice to put angle sensors but would be quite an amount of time to code.
Just be sure to have enough extension cable and spare SMA connectors. We had some antenna cables pinched, easy to put another connector.