Skip to content

Commit fbbf7bc

Browse files
committed
switch ros led to imu and show disk usage
1 parent b4562bb commit fbbf7bc

3 files changed

Lines changed: 222 additions & 7 deletions

File tree

src/gui/gui_main.cc

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,21 @@
2929
#include <mutex>
3030
#include <errno.h>
3131
#include <time.h>
32+
#include <sys/file.h>
33+
#include <unistd.h>
34+
#include <fcntl.h>
3235
#include <QApplication>
3336
#include <QPushButton>
3437
#include <QMetaType>
38+
#include <QMessageBox>
3539
#include <memory>
3640
#include <atomic>
3741

3842
#include "rclcpp/rclcpp.hpp"
3943
#include "sensor_msgs/msg/laser_scan.hpp"
4044
#include "sensor_msgs/msg/image.hpp"
4145
#include "sensor_msgs/msg/joy.hpp"
46+
#include "sensor_msgs/msg/imu.hpp"
4247
#include "cv_bridge/cv_bridge.h"
4348
#include <opencv2/opencv.hpp>
4449
#include <QPixmap>
@@ -53,29 +58,77 @@ using ut_automata::msg::CarStatusMsg;
5358
using sensor_msgs::msg::LaserScan;
5459
using sensor_msgs::msg::Image;
5560
using sensor_msgs::msg::Joy;
61+
using sensor_msgs::msg::Imu;
5662

5763
namespace {
5864
ut_automata_gui::MainWindow* main_window_ = nullptr;
5965
std::atomic_bool run_{true};
6066
std::atomic_bool lidar_okay_{false};
6167
std::atomic_bool joystick_okay_{false};
6268
std::atomic_bool vesc_okay_{false};
69+
std::atomic_bool imu_okay_{false};
6370
std::atomic<float> battery_voltage_{0.0f};
6471
std::atomic_int drive_mode_{0};
6572
std::atomic<float> throttle_{0.0f};
6673
std::atomic<float> steering_{0.0f};
6774
// Track last joystick message time for timeout detection
6875
std::atomic<std::chrono::steady_clock::time_point> last_joystick_time_{std::chrono::steady_clock::time_point{}};
76+
// Track last IMU message time for timeout detection
77+
std::atomic<std::chrono::steady_clock::time_point> last_imu_time_{std::chrono::steady_clock::time_point{}};
6978
// ROS node and subscriptions for proper cleanup
7079
std::shared_ptr<rclcpp::Node> ros_node_ = nullptr;
7180
rclcpp::Subscription<CarStatusMsg>::SharedPtr status_sub_ = nullptr;
7281
rclcpp::Subscription<LaserScan>::SharedPtr lidar_sub_ = nullptr;
7382
rclcpp::Subscription<AckermannCurvatureDriveMsg>::SharedPtr drive_sub_ = nullptr;
7483
rclcpp::Subscription<Image>::SharedPtr camera_sub_ = nullptr;
7584
rclcpp::Subscription<Joy>::SharedPtr joystick_sub_ = nullptr;
85+
rclcpp::Subscription<Imu>::SharedPtr imu_sub_ = nullptr;
7686
std::mutex cleanup_mutex_;
87+
int lock_fd_ = -1; // File descriptor for the lock file
7788
} // namespace
7889

90+
// Function to check if another instance is already running
91+
bool IsAnotherInstanceRunning() {
92+
const char* lock_file_path = "/tmp/ut_automata_gui.lock";
93+
94+
lock_fd_ = open(lock_file_path, O_CREAT | O_RDWR, 0666);
95+
if (lock_fd_ == -1) {
96+
printf("Error: Could not create lock file\n");
97+
return false; // Assume no other instance if we can't create lock file
98+
}
99+
100+
// Try to acquire an exclusive lock (non-blocking)
101+
if (flock(lock_fd_, LOCK_EX | LOCK_NB) == -1) {
102+
if (errno == EWOULDBLOCK) {
103+
//printf("Another instance of the GUI is already running\n");
104+
close(lock_fd_);
105+
lock_fd_ = -1;
106+
return true;
107+
} else {
108+
printf("Error acquiring lock: %s\n", strerror(errno));
109+
close(lock_fd_);
110+
lock_fd_ = -1;
111+
return false; // Assume no other instance on error
112+
}
113+
}
114+
115+
// Write PID to lock file
116+
char pid_str[32];
117+
snprintf(pid_str, sizeof(pid_str), "%d\n", getpid());
118+
write(lock_fd_, pid_str, strlen(pid_str));
119+
120+
return false; // No other instance running
121+
}
122+
123+
// Function to release the instance lock
124+
void ReleaseInstanceLock() {
125+
if (lock_fd_ != -1) {
126+
close(lock_fd_); // This automatically releases the flock
127+
unlink("/tmp/ut_automata_gui.lock"); // Remove the lock file
128+
lock_fd_ = -1;
129+
}
130+
}
131+
79132
void StatusCallback(const CarStatusMsg::SharedPtr msg) {
80133
std::lock_guard<std::mutex> lock(cleanup_mutex_);
81134
if (!run_.load() || main_window_ == nullptr || !rclcpp::ok()) return;
@@ -127,6 +180,16 @@ void JoystickCallback(const Joy::SharedPtr msg) {
127180
joystick_okay_.store(true);
128181
}
129182

183+
// IMU callback - marks IMU as okay when messages are received
184+
void ImuCallback(const Imu::SharedPtr msg) {
185+
std::lock_guard<std::mutex> lock(cleanup_mutex_);
186+
if (!run_.load() || !rclcpp::ok()) return;
187+
188+
// Update the last IMU message timestamp
189+
last_imu_time_.store(std::chrono::steady_clock::now());
190+
imu_okay_.store(true);
191+
}
192+
130193
void* RosThread(void* arg) {
131194
// Don't detach - we need to properly join the thread
132195
// pthread_detach(pthread_self());
@@ -144,6 +207,8 @@ void* RosThread(void* arg) {
144207
"/camera_0/image_raw", 10u, &CameraCallback);
145208
joystick_sub_ = ros_node_->create_subscription<Joy>(
146209
"joystick", 10u, &JoystickCallback);
210+
imu_sub_ = ros_node_->create_subscription<Imu>(
211+
"/imu", 10u, &ImuCallback);
147212

148213
RateLoop loop(5.0);
149214
while (rclcpp::ok() && run_.load()) {
@@ -168,6 +233,19 @@ void* RosThread(void* arg) {
168233
// If we received a message within the timeout, joystick_okay_ is already set to true in the callback
169234
}
170235

236+
// Check IMU timeout - fail if no message received in the last 1 second
237+
auto last_imu = last_imu_time_.load();
238+
if (last_imu.time_since_epoch().count() == 0) {
239+
// No IMU message ever received
240+
imu_okay_.store(false);
241+
} else {
242+
auto time_since_last_imu = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_imu).count();
243+
if (time_since_last_imu > 1000) { // 1 second timeout
244+
imu_okay_.store(false);
245+
}
246+
// If we received a message within the timeout, imu_okay_ is already set to true in the callback
247+
}
248+
171249
try {
172250
rclcpp::spin_some(ros_node_);
173251
} catch (const std::exception& e) {
@@ -182,6 +260,7 @@ void* RosThread(void* arg) {
182260
vesc_okay_.load(),
183261
lidar_okay_.load(),
184262
joystick_okay_.load(),
263+
imu_okay_.load(),
185264
throttle_.load(),
186265
steering_.load());
187266
}
@@ -219,6 +298,10 @@ void* RosThread(void* arg) {
219298
joystick_sub_.reset();
220299
printf("Joystick subscription cleaned up\n");
221300
}
301+
if (imu_sub_) {
302+
imu_sub_.reset();
303+
printf("IMU subscription cleaned up\n");
304+
}
222305
} catch (const std::exception& e) {
223306
printf("Exception during subscription cleanup: %s\n", e.what());
224307
}
@@ -243,6 +326,7 @@ void* RosThread(void* arg) {
243326
drive_sub_.reset();
244327
camera_sub_.reset();
245328
joystick_sub_.reset();
329+
imu_sub_.reset();
246330
ros_node_.reset();
247331
}
248332
}
@@ -257,6 +341,9 @@ void SignalHandler(int num) {
257341
printf("\nReceived signal %d, shutting down gracefully...\n", num);
258342
run_.store(false);
259343

344+
// Release the instance lock
345+
ReleaseInstanceLock();
346+
260347
// Give the ROS thread time to process the shutdown signal
261348
std::this_thread::sleep_for(std::chrono::milliseconds(200));
262349

@@ -269,6 +356,18 @@ void SignalHandler(int num) {
269356
}
270357

271358
int main(int argc, char *argv[]) {
359+
// Check if another instance is already running
360+
if (IsAnotherInstanceRunning()) {
361+
//// Create a minimal QApplication to show the message box
362+
//QApplication app(argc, argv);
363+
//QMessageBox::warning(nullptr,
364+
// "UT Automata GUI",
365+
// "Another instance of the GUI is already running.\n"
366+
// "Only one instance is allowed at a time.",
367+
// QMessageBox::Ok);
368+
return 1;
369+
}
370+
272371
rclcpp::init(argc, argv);
273372
signal(SIGINT, &SignalHandler);
274373
qRegisterMetaType<std::vector<std::string> >("std::vector<std::string>");
@@ -326,5 +425,8 @@ int main(int argc, char *argv[]) {
326425
printf("rclcpp already shut down.\n");
327426
}
328427

428+
// Release the instance lock before exiting
429+
ReleaseInstanceLock();
430+
329431
return retval;
330432
}

0 commit comments

Comments
 (0)