-
Notifications
You must be signed in to change notification settings - Fork 2
[CPP-154]Fusion Engine Status Bar for Advanced->INS tab. #71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CPP-154]Fusion Engine Status Bar for Advanced->INS tab. #71
Conversation
I attempted comparing the output visually with the old console but seem to be unable to get the "realtime playback" feature to work correctly. I have been using this command and it blows through the 5min file in a few seconds: |
const SET_STATUS_THREAD_SLEEP_SEC: f64 = 0.05; | ||
|
||
// No updates have been attempted in the past `STATUS_PERIOD` | ||
const UNKNOWN: &str = "\u{2B1B}"; // Unicode Character “⬛” (U+2B1B) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know @ notoriaga you probably used these unicode chars because of limitations with the traits api but we could switch to svgs if it is preferred. I would probably rewrite the logic a bit to use a shared enum (maybe save this for a future PR)
Another limitation if not already apparent is the OK circle seems to be hard anchored to the top right corner of the text space so fast switching between status' shows a noticeable shift.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm yea the unicode characters were because it was the only thing we could get working, so if svgs behave better i'd say go for it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
brutal that may be cause I did not set the font size however that would not explain why the color does not show up 😕
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have switched to using svgs and the color's look to be working on Linux + Windows.
is_running.set(true); | ||
spawn(move || { | ||
let mut expired = false; | ||
while is_running.get() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main reason I went with implementing my own timer thread was that I couldn't find a decent crate which provided the ability to cancel a timer (preventing any remaining functionality from executing). Not that this approach does that per se but the logic in the "restart_timer" would prevent a thread that continues executing but did not expire to not set the value as it would had it expired assuming "is_running" gets set false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explanation gets confusing towards the end, can you rephrase?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of rephrasing I will just ask to re-review the timer code as I have now switched toward using crossbeam's after feature. I think it is definitely less complex but seems slightly more reliable. I couldn't best figure out how to keep track of whether or not the timer was running so I have a manually set atomic bool keep track of this now.
f6dd5a7
to
ab1d91b
Compare
}; | ||
use crate::types::{IsRunning, MessageSender, SharedState}; | ||
|
||
const STATUS_PERIOD: f64 = 1.0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wondering if it might be worth increasing this status_period here to say 1.1. I think due to the nature of not using callbacks/async, or simply just that this code is not very efficient, the time it takes to cancel/reset the unknown timer when a new message comes in takes too long and will display an unknown for a split second in the case of a pattern such as:
MsgInsUpdates { sender_id: Some(789), tow: 413750200, gnsspos: 16, gnssvel: 0, wheelticks: 0, speed: 0, nhc: 0, zerovel: 0 }
MsgInsUpdates { sender_id: Some(789), tow: 413750300, gnsspos: 0, gnssvel: 0, wheelticks: 0, speed: 0, nhc: 0, zerovel: 0 }
MsgInsUpdates { sender_id: Some(789), tow: 413750400, gnsspos: 0, gnssvel: 0, wheelticks: 0, speed: 0, nhc: 16, zerovel: 17 }
MsgInsUpdates { sender_id: Some(789), tow: 413750500, gnsspos: 0, gnssvel: 0, wheelticks: 0, speed: 0, nhc: 0, zerovel: 0 }
MsgInsUpdates { sender_id: Some(789), tow: 413750600, gnsspos: 0, gnssvel: 16, wheelticks: 0, speed: 0, nhc: 0, zerovel: 0 }
MsgInsUpdates { sender_id: Some(789), tow: 413750700, gnsspos: 0, gnssvel: 16, wheelticks: 0, speed: 0, nhc: 0, zerovel: 0 }
MsgInsUpdates { sender_id: Some(789), tow: 413750800, gnsspos: 0, gnssvel: 16, wheelticks: 0, speed: 0, nhc: 0, zerovel: 0 }
MsgInsUpdates { sender_id: Some(789), tow: 413750900, gnsspos: 0, gnssvel: 16, wheelticks: 0, speed: 0, nhc: 0, zerovel: 0 }
MsgInsUpdates { sender_id: Some(789), tow: 413751000, gnsspos: 0, gnssvel: 16, wheelticks: 0, speed: 0, nhc: 0, zerovel: 0 }
MsgInsUpdates { sender_id: Some(789), tow: 413751100, gnsspos: 0, gnssvel: 16, wheelticks: 0, speed: 0, nhc: 0, zerovel: 0 }
MsgInsUpdates { sender_id: Some(789), tow: 413751200, gnsspos: 16, gnssvel: 17, wheelticks: 0, speed: 0, nhc: 16, zerovel: 0 }
where the gnsspos is displaying Ok
every 1 full second. This can be seen playing the example file in the PR description.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds reasonable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the rewrite in code has reduced this problem somewhat. We could still bump it up and it could reduce the issue even more but for now I think it looks ok. Still think the issue is just that small amount of compute time spent getting the OK message registered before the Unknown timer procs and sets it to unknown.
ab1d91b
to
a8bb03e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some initial comments, will review more this afternoon
console_backend/src/errors.rs
Outdated
@@ -1,6 +1,14 @@ | |||
pub const HEARTBEAT_LOCK_MUTEX_FAILURE: &str = "unable to lock heartbeat mutex"; | |||
pub const SHARED_STATE_LOCK_MUTEX_FAILURE: &str = "unable to lock shared_state mutex"; | |||
pub const IS_RUNNING_LOCK_MUTEX_FAILURE: &str = "unable to lock is_running mutex"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not used anymore? All of these constants should probably be pub(crate)
since we're not a library-- changing to pub(crate)
will help identify unused constants that we can delete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. There is one I had to add an allow dead_code because it is used by the server.rs in one of the "disabled features" functions. This may be resolved in @notoriaga PR in which we could remove this allow then.
}; | ||
use crate::types::{IsRunning, MessageSender, SharedState}; | ||
|
||
const STATUS_PERIOD: f64 = 1.0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds reasonable
) -> JoinHandle<()> { | ||
let start_time = Instant::now(); | ||
let mut storage = storage; | ||
is_running.set(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to set this inside the thread itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
delay: f64, | ||
) -> JoinHandle<()> { | ||
let start_time = Instant::now(); | ||
let mut storage = storage; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be able to just mark the storage
parameter itself as mut
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
is_running.set(false); | ||
break; | ||
} | ||
sleep(Duration::from_millis(5)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The longer we can sleep here the better-- an alternate might be to wait for an event signal with a timeout, this would allow us to immediately wake up the thread if we wanted to cancel, but also sleep for a longer amount of time to lower the CPU burden. You can also randomize the sleep a bit to try to spread out the processor load.
See https://doc.rust-lang.org/std/sync/struct.Condvar.html#method.wait_timeout
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switching to channels I think it accomplishes this and now the timeout is around 250ms so not too bad.
} | ||
|
||
fn set_status_thread(&mut self) { | ||
self.is_running.set(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be preferable to set this inside the thread if possible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
} | ||
|
||
fn stop(&mut self) { | ||
self.is_running.set(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this wait to join the thread so we can be sure the thread stopped?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, one obvious problem with waiting for the thread to exit: we'd have to wait for the sleep timer to expire, if we used a condvar as I suggested above we can immediately make the thread exit, then here waiting for the thread to exit shouldn't be an issue. The logic would something like this:
In the thread:
- Do stuff
- Wait on condvar for current sleep interval
- If condvar fires, exit the thread, else loop again
In the stop
call:
- Signal the condvar
- Wait for the thread to exit (up to a limit, say 1 second)
- Exit successfully or log and error if the thread doesn't exit (panicking might be appropriate too)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have set up the main loop to wait for a received Option if it gets None passed in that triggers the exit condition. I believe there is not much wait time now. I added a join to the stop and cancel commands as well.
is_running.set(true); | ||
spawn(move || { | ||
let mut expired = false; | ||
while is_running.get() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explanation gets confusing towards the end, can you rephrase?
const OK: &str = "\u{26AB}"; // Unicode Character “⚫” (U+26AB) | ||
|
||
#[derive(Debug)] | ||
pub struct UpdateStatus(Arc<Mutex<Option<UpdateStatusInner>>>); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub struct UpdateStatus(Arc<Mutex<Option<UpdateStatusInner>>>); | |
pub struct FusionStatus(Arc<Mutex<Option<FusionStatusInner>>>); |
} | ||
|
||
#[derive(Debug)] | ||
struct FlagStatus { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
struct FlagStatus { | |
struct FusionStatusFlag |
} | ||
|
||
fn stop(&mut self) { | ||
self.is_running.set(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, one obvious problem with waiting for the thread to exit: we'd have to wait for the sleep timer to expire, if we used a condvar as I suggested above we can immediately make the thread exit, then here waiting for the thread to exit shouldn't be an issue. The logic would something like this:
In the thread:
- Do stuff
- Wait on condvar for current sleep interval
- If condvar fires, exit the thread, else loop again
In the stop
call:
- Signal the condvar
- Wait for the thread to exit (up to a limit, say 1 second)
- Exit successfully or log and error if the thread doesn't exit (panicking might be appropriate too)
/// - `nhc`: Storage for the non-holonomic constraints model status. | ||
/// - `zerovel`: Storage for the zero velocity status. | ||
#[derive(Debug)] | ||
pub struct FusionEngineStatus<S: MessageSender> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub struct FusionEngineStatus<S: MessageSender> { | |
pub struct FusionStatusFlags<S: MessageSender> { |
let mut msg_bytes: Vec<u8> = vec![]; | ||
serialize::write_message(&mut msg_bytes, &builder) | ||
.expect(CAP_N_PROTO_SERIALIZATION_FAILURE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This really feels like we could have a helper for this:
- Allocate a vector
- Write/serialize a message (and panic/expect)
- (Potentially also) send a message to the supplied client sender
|
||
impl<S: MessageSender> Drop for FusionEngineStatus<S> { | ||
fn drop(&mut self) { | ||
self.gnsspos.stop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be implemented on each object rather than here
console_backend/src/types.rs
Outdated
} | ||
|
||
#[derive(Debug, Default)] | ||
pub struct IsRunning(Arc<AtomicBool>); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub struct IsRunning(Arc<AtomicBool>); | |
pub struct ArcBool(Arc<AtomicBool>); |
Or maybe:
pub struct IsRunning(Arc<AtomicBool>); | |
pub struct SingletonBool(Arc<AtomicBool>); |
d01c4d3
to
440b17d
Compare
cb024c2
to
30c29c2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
30c29c2
to
7152d2a
Compare
If you want to see a file with a few Ok/Warnings you can pull lfs and then run.