PARTIALLY SOLVED…
So I traced the issue being to these lines of code associated with the OLED.
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library.
// On an arduino UNO: A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO: 2(SDA), 3(SCL), ...
// Reset pin not used but needed for library
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
//Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display(OLED_RESET);
When I just use Adafruit_SSD1306 display(OLED_RESET); , by the way the OLED is just a 4pin board with no reset pin, the display comes to life and shows the results I’m after. However I now obviously lose the capability of the SCREEN_WIDTH and SCREEN_HEIGHT.
Looking at the Adafruit_SSD1306.h and the class Adafruit_SDD1306 : public Adafruit_GFX…inside public: is this constructor…
// NEW CONSTRUCTORS – recommended for new projects
Adafruit_SSD1306(uint8_t w, uint8_t h, TwoWire *twi = &Wire,
int8_t rst_pin = -1, uint32_t clkDuring = 400000UL,
uint32_t clkAfter = 100000UL);
inside protected is…
TwoWire *wire; ///< Initialized during construction when using I2C. See
///< Wire.cpp, Wire.h
So my question is HOW do I make full use of the OLED display when using SCREEN_WIDTH, SCREEN_HEIGHT, &WIRE which appear to be the root cause of my original problem as previously posted below???
Hi All,
Been awhile since I last posted as I continue my self learning. I’ve looked through other posts to see if there’s anything similar to my problem but can’t see anything, apologies if anyone knows of one.
I have a working example of code I’m using based on Paul McWhorters Tutorials for the BNO055 displaying the dynamic state of variables like Acceleration etc.
I decided to try and implement the restore_offsets example into my code to relieve the issue of calibrating each time I power up apart from the magnetometer value.
by implementing the code from the restore_offsets example I seem to have generated a conflict somewhere as the OLED display has ceased to function. It looks like it isn’t updating from the I2C bus yet when I use Serial.print statements they are printed to the Terminal perfectly??
A little stumped at the moment hoping for some guidance please.
main.cpp file
#include <Arduino.h>
#include <Wire.h>
#include <math.h> //Header file from Tut 6
#include <Adafruit_Sensor.h> /******************************/
#include <Adafruit_BNO055.h> /* Header files from Tutorial */
#include <utility/imumaths.h> /* */
/******************************/
#include <EEPROM.h> //Header file from Calibration Example
#include <Adafruit_I2CDevice.h> /*************************/
#include <Adafruit_BusIO_Register.h> /* Header files req'd by */
/* Platformio */
/*************************/
//Header files for added OLED display
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define I2C_ADDRESS 0x28 //0x29 /* Definition taken from Example */
Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(I2C_ADDRESS); /* Class instantiation */
#define BNO055_SAMPLERATE_DELAY_MS (100)
#define PI 3.1415926535897932384626433832795
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library.
// On an arduino UNO: A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO: 2(SDA), 3(SCL), ...
// Reset pin not used but needed for library
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//Initialise Filter values
float thetaFold = 0;
float phiFold = 0;
float psiFold = 0;
float thetaG = 0;
float phiG = 0;
float theta; // Variable used in loop code, theta = calculated Pitch
float phi; // Variable used in loop code, psi = calculated Roll
unsigned long millisOld;
//Create a BNO055 Object called myIMU
Adafruit_BNO055 myIMU = Adafruit_BNO055(55,0x28); //Updated from Adafruit_BNO055 example
/**************************************************************************/
/*
Display sensor calibration status
*/
/**************************************************************************/
int displayCalStatus(void)
{
/* Get the four calibration values (0..3) */
/* Any sensor data reporting 0 should be ignored, */
/* 3 means 'fully calibrated" */
uint8_t system, gyro, accel, mg;
system = gyro = accel = mg = 0;
int Acceleration;
Acceleration = 0;
myIMU.getCalibration(&system, &gyro, &accel, &mg);
/* The data should be ignored until the system calibration is > 0 */
if (accel < 3)
{
Acceleration = accel;
digitalWrite(4, HIGH);
delay (50);
digitalWrite(4,LOW);
delay (50);
}
else if (accel == 3)
{ digitalWrite(4, HIGH);
Acceleration = 3;
}
if (system == 3)
{ digitalWrite(2, HIGH); }
else if (system < 1)
{
digitalWrite(2, LOW);
digitalWrite(3, HIGH);
delay (50);
digitalWrite(3,LOW);
delay (50);
}
return Acceleration;
}
/**************************************************************************/
/*
Display the raw calibration offset and radius data
*/
/**************************************************************************/
void displaySensorOffsets(const adafruit_bno055_offsets_t &calibData)
{
Serial.print("Accelerometer: ");
Serial.print(calibData.accel_offset_x); Serial.print(" ");
Serial.print(calibData.accel_offset_y); Serial.print(" ");
Serial.print(calibData.accel_offset_z); Serial.print(" ");
Serial.print("\nGyro: ");
Serial.print(calibData.gyro_offset_x); Serial.print(" ");
Serial.print(calibData.gyro_offset_y); Serial.print(" ");
Serial.print(calibData.gyro_offset_z); Serial.print(" ");
Serial.print("\nMag: ");
Serial.print(calibData.mag_offset_x); Serial.print(" ");
Serial.print(calibData.mag_offset_y); Serial.print(" ");
Serial.print(calibData.mag_offset_z); Serial.print(" ");
Serial.print("\nAccel Radius: ");
Serial.print(calibData.accel_radius);
Serial.print("\nMag Radius: ");
Serial.print(calibData.mag_radius);
}
void setup()
{
Serial.begin(115200);
myIMU.begin();
delay(1000);
//int8_t temp = myIMU.getTemp();
//Serial.println(temp);
//myIMU.setExtCrystalUse(true);
int eeAddress = 0;
long bnoID;
bool foundCalib = false;
EEPROM.get(eeAddress, bnoID);
adafruit_bno055_offsets_t calibrationData;
sensor_t sensor;
/*
* Look for the sensor's unique ID at the beginning oF EEPROM.
* This isn't foolproof, but it's better than nothing.
*/
myIMU.getSensor(&sensor);
if (bnoID != sensor.sensor_id)
{
Serial.println("\nNo Calibration Data for this sensor exists in EEPROM");
delay(500);
}
else
{
Serial.println("\nFound Calibration for this sensor in EEPROM.");
eeAddress += sizeof(long);
EEPROM.get(eeAddress, calibrationData);
displaySensorOffsets(calibrationData);
Serial.println("\n\nRestoring Calibration data to the BNO055...");
myIMU.setSensorOffsets(calibrationData);
Serial.println("\n\nCalibration data loaded into BNO055");
foundCalib = true;
}
delay(1000);
/* Display some basic information on this sensor */
//displaySensorDetails();
/* Optional: Display current status */
//displaySensorStatus();
sensors_event_t event;
myIMU.getEvent(&event);
/* always recal the mag as It goes out of calibration very often */
if (foundCalib)
{
Serial.println("Move sensor slightly to calibrate magnetometers");
while (!myIMU.isFullyCalibrated())
{
myIMU.getEvent(&event);
delay(BNO055_SAMPLERATE_DELAY_MS);
}
}
else
{
Serial.println("Please Calibrate Sensor: ");
while (!myIMU.isFullyCalibrated())
{
myIMU.getEvent(&event);
Serial.print("X: ");
Serial.print(event.orientation.x, 4);
Serial.print("\tY: ");
Serial.print(event.orientation.y, 4);
Serial.print("\tZ: ");
Serial.print(event.orientation.z, 4);
/* Optional: Display calibration status */
//displayCalStatus();
/* New line for the next sample */
Serial.println("");
/* Wait the specified delay before requesting new data */
delay(BNO055_SAMPLERATE_DELAY_MS);
}
}
Serial.println("\nFully calibrated!");
Serial.println("--------------------------------");
Serial.println("Calibration Results: ");
adafruit_bno055_offsets_t newCalib;
myIMU.getSensorOffsets(newCalib);
displaySensorOffsets(newCalib);
Serial.println("\n\nStoring calibration data to EEPROM...");
eeAddress = 0;
myIMU.getSensor(&sensor);
bnoID = sensor.sensor_id;
EEPROM.put(eeAddress, bnoID);
eeAddress += sizeof(long);
EEPROM.put(eeAddress, newCalib);
Serial.println("Data stored to EEPROM.");
Serial.println("\n--------------------------------\n");
delay(500);
/* Crystal must be configured AFTER loading calibration data into BNO055. */
myIMU.setExtCrystalUse(true);
// Initialize OLED with I2C addr 0x3C
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
millisOld = millis();
}
void loop()
{
// Put your main code here, to run repeatedly:
// Variables used in Calculations
float thetaM, thetaFnew, thetaRad;
float phiM, phiFnew, phiRad;
float psiFnew; //NEW CODE
// Filter Gain values where sum=1
float thetaFoldGain = 0.9;
float phiFoldGain = 0.9;
float psiFoldGain = 0.85; //NEW CODE
float thetaMGain = 0.1;
float phiMGain = 0.1;
float psiMGain = 0.15; //NEW CODE
float dt; //Time variable between loop calculations
// Magnetometer variables
float Xm;
float Ym;
float psi;
int Acceleration;
display.display();
/* Display Calibration Values/Status */
Acceleration = displayCalStatus();
//Open AdaFruit Library imu and get data put into Vector<>
imu::Vector<3> acc = myIMU.getVector(Adafruit_BNO055::VECTOR_ACCELEROMETER);
imu::Vector<3> gyr = myIMU.getVector(Adafruit_BNO055::VECTOR_GYROSCOPE);
imu::Vector<3> mag = myIMU.getVector(Adafruit_BNO055::VECTOR_MAGNETOMETER);
//Calculate Pitch and Roll angles from Accelerometers & Gyros Lesson 7 & 8
//Apply Low Pass Filter calculation
thetaM = -atan2(acc.x()/9.8,acc.z()/9.8)/2/PI*360; //Pitch from Accelerometer
thetaFnew = thetaFoldGain*thetaFold + thetaMGain*thetaM;
phiM = -atan2(acc.y()/9.8,acc.z()/9.8)/2/PI*360; //Roll from Accelerometer
phiFnew = phiFoldGain*phiFold + phiMGain*phiM;
//Calculate the time between measurements
dt = (millis() - millisOld)/1000.0;
millisOld = millis();
//Lesson 9 Apply a Complimentary Filter for short term changes and long term stability
//Pitch value theta = short term value of GYRO (HIGH PASS FILTER) + long term value of ACCELEROMETER (LOW PASS FILTER)
theta = (theta + gyr.y()*dt)*thetaFoldGain + thetaM*thetaMGain;
//Roll value phi = short term value of GYRO (HIGH PASS FILTER) + long term value of ACCELEROMETER (LOW PASS FILTER)
phi = (phi - gyr.x()*dt)*phiFoldGain + phiM*phiMGain;
//Arduino works in RADIANS for sin, cos, tan calculations
thetaRad = theta/360*(2*PI);
phiRad = phi/360*(2*PI);
//Calculate compensated psi (mag) value for the Pitch and Roll vectors
Xm = mag.x()*cos(thetaRad) - mag.y()*sin(phiRad)*sin(thetaRad) + mag.z()*cos(phiRad)*sin(thetaRad);
Ym = mag.y()*cos(phiRad) + mag.z()*sin(phiRad);
//Calculate Magnetic North in degrees
psi=atan2(Ym,Xm)/(2*PI)*360;
psiFnew = psiFoldGain*psi + psiMGain*psiFold; //NEW CODE
/*
Serial.print(theta);
Serial.print(", ");
Serial.print(phi);
Serial.print(", ");
Serial.print(psi);
Serial.print(", ")
Serial.print(Acceleration)
Serial.println(", ");
*/
// Clear the display
display.clearDisplay();
//Set the color - always use white despite actual display color
display.setTextColor(WHITE);
//Set the font size
display.setTextSize(1.5);
//Set the cursor coordinates
display.setCursor(0,0);
display.print("Pitch: ");
display.print(theta);
display.setCursor(0,10);
display.print("Roll: ");
display.print(phi);
display.setCursor(0,20);
display.print("Yaw: ");
display.print(psiFnew);
display.setCursor(0,30);
display.print("Acceleration: ");
display.print(Acceleration);
display.setCursor(0,40);
thetaFold = thetaFnew; //Update theta filter old value
phiFold = phiFnew; //Update phi filter old value
psiFold = psiFnew;
delay (BNO055_SAMPLERATE_DELAY_MS);
}
platform.ini file
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:nanoatmega328]
platform = atmelavr
board = nanoatmega328
framework = arduino
monitor_speed = 115200
lib_deps =
adafruit/Adafruit BNO055@^1.6.3
adafruit/Adafruit Unified Sensor@^1.1.14
adafruit/Adafruit BusIO@^1.14.5
adafruit/Adafruit SSD1306@^2.5.9
Made a few changes to the program and determined at the point where the loop hangs, but it’s a little beyond my understanding as to why at the moment?
when I un-comment the line display.setTextColor(WHITE); the code just hangs for some reason?
/* Display Calibration Values/Status */
Acceleration = displayCalStatus();
Serial.print(theta);
Serial.print(", ");
Serial.print(phi);
Serial.print(", ");
Serial.print(psi);
Serial.print(", ");
Serial.print(Acceleration);
Serial.println(", ");
// Clear the display
display.clearDisplay();
//Set the font size
display.setTextSize(1.5);
//Set the color - always use white despite actual display color
display.setTextColor(WHITE); //Loop hangs at this point after printing 1 line of results from above???
//Set the cursor coordinates
display.setCursor(0,0);
display.print("Pitch: ");
FINALLY traced it to when the first OLED display.print("Pitch: "); instruction is executed the program produces an unexpected event??? OR an OLED display.print instruction is executed,
It prints 2 lines of 0.0, 0.0, 0.0, 3
Then prints 2 lines of values before hanging up and executing the setup() function again???
Bit beyond my knowledge/understanding this at the moment as to why.
My other program using the OLED display without the modification to use restore_offsets works perfectly ???