So, I need help. My code uses an MPU6050 and a filter to smooth out the angles, it then uses an HC-SR04 to measure the height from the ground. It displays both the angles and the height from the ground to the LCD Screen, but I'm trying to find a way to change the LCD screen through a button push to show the Distance of the observer to the object and the height of the object. In my code I've been trying for the past few hours to change this but the closest I've ever gotten was just a flickering between the 2 modes of the screen (which is this code.) This uses an ESP32-WROOM
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <NewPing.h>
#define TRIG_PIN 5
#define ECHO_PIN 18
#define MAX_DISTANCE 400 // Maximum distance for HC-SR04 in cm
#define BUTTON_PIN 4 // Pin connected to the button
// Variables for Kalman filter
float RateRoll, RatePitch;
float AccX, AccY, AccZ;
float AngleRoll, AnglePitch;
float KalmanAngleRoll = 0, KalmanUncertaintyAngleRoll = 2 * 2;
float KalmanAnglePitch = 0, KalmanUncertaintyAnglePitch = 2 * 2;
uint32_t LoopTimer;
float Kalman1DOutput[] = {0, 0};
// Variables for height and distance calculation
float userHeight = 0; // User height from HC-SR04
float partialHeight = 0; // Partial height of the object
float distanceToObject = 0; // Distance to the object
bool calculateDistance = false; // Flag to toggle display mode
unsigned long lastButtonPress = 0; // Last button press time
const unsigned long debounceDelay = 200; // Debounce delay
LiquidCrystal_I2C lcd(0x27, 16, 2);
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE);
void kalman_1d(float &KalmanState, float &KalmanUncertainty, float KalmanInput, float KalmanMeasurement) {
KalmanState = KalmanState + 0.004 * KalmanInput;
KalmanUncertainty = KalmanUncertainty + 0.004 * 0.004 * 4 * 4;
float KalmanGain = KalmanUncertainty / (KalmanUncertainty + 3 * 3);
KalmanState = KalmanState + KalmanGain * (KalmanMeasurement - KalmanState);
KalmanUncertainty = (1 - KalmanGain) * KalmanUncertainty;
Kalman1DOutput[0] = KalmanState;
Kalman1DOutput[1] = KalmanUncertainty;
}
void gyro_signals() {
Wire.beginTransmission(0x68);
Wire.write(0x3B);
Wire.endTransmission();
Wire.requestFrom(0x68, 6);
int16_t AccXLSB = Wire.read() << 8 | Wire.read();
int16_t AccYLSB = Wire.read() << 8 | Wire.read();
int16_t AccZLSB = Wire.read() << 8 | Wire.read();
AccX = (float)AccXLSB / 4096;
AccY = (float)AccYLSB / 4096;
AccZ = (float)AccZLSB / 4096;
AngleRoll = atan(AccY / sqrt(AccX * AccX + AccZ * AccZ)) * 180 / PI;
AnglePitch = -atan(AccX / sqrt(AccY * AccY + AccZ * AccZ)) * 180 / PI;
}
void setup() {
Serial.begin(115200);
Wire.begin();
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Initializing...");
delay(1000);
Wire.beginTransmission(0x68);
Wire.write(0x6B);
Wire.write(0x00);
Wire.endTransmission();
pinMode(BUTTON_PIN, INPUT);
LoopTimer = micros();
}
void loop() {
gyro_signals();
kalman_1d(KalmanAngleRoll, KalmanUncertaintyAngleRoll, 0, AngleRoll);
kalman_1d(KalmanAnglePitch, KalmanUncertaintyAnglePitch, 0, AnglePitch);
userHeight = sonar.ping_cm();
// Check for button press
if (digitalRead(BUTTON_PIN) == HIGH) {
if (millis() - lastButtonPress > debounceDelay) { // Check for debounce
calculateDistance = !calculateDistance; // Toggle between modes
lastButtonPress = millis(); // Update last button press time
}
}
if (calculateDistance) {
partialHeight = tan(abs(KalmanAngleRoll * PI / 180)) * userHeight;
float totalHeight = userHeight + partialHeight;
lcd.setCursor(0, 0);
lcd.print("Height: ");
lcd.print(totalHeight);
lcd.print(" cm");
lcd.setCursor(0, 1);
lcd.print("Distance: ");
lcd.print(userHeight / tan(abs(KalmanAngleRoll * PI / 180)));
lcd.print(" cm");
} else {
lcd.setCursor(0, 0);
lcd.print("Roll: ");
lcd.print(KalmanAngleRoll);
lcd.print(" deg");
lcd.setCursor(0, 1);
lcd.print("Height: ");
lcd.print(userHeight);
lcd.print(" cm");
}
while (micros() - LoopTimer < 4000);
LoopTimer = micros();
}
[quote="HaroldTech, post:1, topic:278543, full:true"]
Hi, I need help with the programming of my latest project. So I have a 16 x 2 LCD display and I had it displaying Something. So every time a button is pressed, I want the screen to change its text. the button is connected to port 2. Thanks for your help!
[/quote]
You have to ensure to void the button from the moment it's read as pushed once, and "rearm" it for a new use after it's released.
You can see the solution implemented in (or just directly use) the ButtonToSwitch library, using the SnglSrvcVdblMPBttn class. Use the methods to set a function to execute when the button enters the isOn state, using the setFnWhnTrnOnPtr() method, and set the function to do the calculateDistance value swapping.
I believe the 13_SnglSrvcVdblMPBttn_1e.ino example file shows how to implement that pretty simple, about 6 lines of code...
Given Supercalifragilisticespialidosus name was taken (but hey, you've got a point, everybody remembers it after 50 or 60 year!!), SingleServiceVoidableMomentaryPushButton seemed to me the same as the name without a vowel and it is: An awful name everybody will copy instead of trying to remember and transcrip so the shortest copy...
BTW Thank you very much for your fork of the TimerOne library to include UNO-R4, I was about to drop TimerOne dependency as an option to my library!! Great Job!