I'll preface this with, I know just enough Arduino/C++ to get in over my head.
I'm interfacing with a PS2 optical mouse using the PS2 mouse handler library.
The device hangs after a period of time with no mouse movement (about 1 hour) but will hang sooner with movement.
I'm looking at the char arrays as the culprit, but I'm unsure of the mechanism behind the hang and so don't really know where to go from here. You're asking 'why on earth am I using char arrays?' The full sketch has a bunch of other functionality, and the function that acts on the mouse data (OpenWeather library) is looking for these values in that format to send to a web API.
The issue is present in the following code.
/*
Uses PS2MouseHandler library to read a PS2 optical mouse
Hardware is Arduino Nano ESP32, HP PS\2 optical mouse with PAW3402 sensor chip, and a globe of the earth
Moving the mouse along the surface of the globe translates mouse xy movements to lat long
Contains code from various sources because spherical trigonometry is over my head
Calibration is performed by rotating the globe to the 'home' position, then reboot
*/
#include <Arduino.h>
#include <math.h>
#include <PS2MouseHandler.h>
const byte MOUSE_DATA = 8;
const byte MOUSE_CLOCK = 9;
struct Point {
double x;
double y;
};
unsigned long globeTimer = millis();
Point mousePoint = {0,0};
Point currentLatLong = {32.0,-117.0}; // home location
const Point ORIGIN = {0, 0}; // origin is always 0.0
PS2MouseHandler mouse(MOUSE_CLOCK, MOUSE_DATA, PS2_MOUSE_REMOTE);
const double GLOBE_R = 6.0; // globe raduis in inches
const double MOUSE_RES = 1000; // mouse resolution in pixels per inch.
const double GLOBE_SCALE = (MOUSE_RES * GLOBE_R);
//Original sketch needed the values as char arrays to pass into other functions, so we're doing some conversions
char computedLat[20] = "";
char computedLong[20] = "";
char *Lat = "";
char *Long = "";
void setup() {
Serial.begin(115000);
if(mouse.initialise() != 0){
Serial.println("mouse error");
};
mouse.set_resolution(MOUSE_RES); //the PAW3402 can be set to 500, 800, or 1000
// do other setup here
}
void loop() {
globe(); //check for updates
if (millis() - globeTimer > 1000) { //serial output once per second
globeTimer = millis();
Serial.print("Lattitude : ");
Serial.println(Lat);
Serial.print("Longitude : ");
Serial.println(Long);
}
//put code here
}
void globe() {
mouse.get_data(); //get mouse movements
mousePoint = {mouse.x_movement(), (mouse.y_movement() * -1.0)}; //invert y and scale the mouse movement to the size of the earth
currentLatLong = calculateDestination(currentLatLong.x, currentLatLong.y, getVector(mousePoint).x, getVector(mousePoint).y); //compute our new lat long
dtostrf(currentLatLong.x, 12, 6, computedLat); //convert to char array
dtostrf(currentLatLong.y, 12, 6, computedLong);
Lat = trimWhitespace(computedLat, sizeof(computedLat)); //and trim
Long = trimWhitespace(computedLong, sizeof(computedLong));
}
Point getVector(Point point2) { //get bearing and distance based on mouse movement
return {toDegrees(calculateBearing(ORIGIN, point2)), calculateDistance(ORIGIN, point2)};
}
// Calculate destination point given a starting point, bearing, and distance
Point calculateDestination(double startLat, double startLon, double bearing2, double distance2) {
double delta = distance2 / GLOBE_SCALE; // Angular distance in radians using the scaling factor
double lat1 = toRadians(startLat);
double lon1 = toRadians(startLon);
double brng = toRadians(bearing2);
double lat2 = asin(sin(lat1) * cos(delta) + cos(lat1) * sin(delta) * cos(brng));
double lon2 = lon1 + atan2(sin(brng) * sin(delta) * cos(lat1), cos(delta) - sin(lat1) * sin(lat2));
// Normalize longitude to be between -180 and 180 degrees
lon2 = fmod(lon2 + 3 * PI, 2 * PI) - PI;
return {toDegrees(lat2), toDegrees(lon2)};
}
// Convert degrees to radians
double toRadians(double degrees) {
return degrees * PI / 180.0;
}
// Convert radians to degrees
double toDegrees(double radians) {
return radians * 180.0 / PI;
}
// Calculate bearing between two points
double calculateBearing(Point oldP, Point newP) {
double dx = newP.x - oldP.x;
double dy = newP.y - oldP.y;
double angle = atan2(dy, dx);
return fmod(toRadians(90.0) - angle, 2 * PI); // Convert to standard bearing
}
// Calculate distance between two points
double calculateDistance(Point oldP, Point newP) {
double dx = newP.x - oldP.x;
double dy = newP.y - oldP.y;
return sqrt(dx*dx + dy*dy);
}
char* trimWhitespace(char* str, int length) { // this isn't needed if you don't need output in char array
int start = 0;
int end = length - 1;
while (start < length && (str[start] == ' ' || str[start] == '\t' || str[start] == '\n')) {// Find the start index of non-whitespace characters
start++;
}
while (end >= start && (str[end] == ' ' || str[end] == '\t' || str[end] == '\n')) { // Find the end index of non-whitespace characters
end--;
}
for (int i = start; i <= end; i++) {// Move characters to the beginning of the array
str[i - start] = str[i];
}
str[end - start + 1] = '\0';// Null-terminate the trimmed string
return str;
}
7 posts - 3 participants