Observe scheduled Move hues through PSMoveAPI
This commit is contained in:
parent
6bf62106dc
commit
8dc7dcd172
4 changed files with 172 additions and 9 deletions
|
|
@ -4255,13 +4255,29 @@ fn publish_move_controller_states(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn active_move_marker_camera_sources(options: &Options) -> Vec<ActiveMoveMarkerCameraSource> {
|
fn active_move_marker_camera_sources(options: &Options) -> Vec<ActiveMoveMarkerCameraSource> {
|
||||||
let move_colors: Vec<(String, [u8; 3])> = serve_move_state_sources(options, true)
|
let mut move_roster = serve_move_state_sources(options, true)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|source| {
|
.map(|source| source.move_id)
|
||||||
let (red, green, blue) = default_move_color_for_identity(&source.move_id);
|
.collect::<Vec<_>>();
|
||||||
(source.move_id, [red, green, blue])
|
move_roster.sort();
|
||||||
|
move_roster.dedup();
|
||||||
|
let now_ns = SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.as_nanos() as i128;
|
||||||
|
let move_colors = move_roster
|
||||||
|
.iter()
|
||||||
|
.filter_map(|identity| {
|
||||||
|
scheduled_golden_move_color(
|
||||||
|
identity,
|
||||||
|
&move_roster,
|
||||||
|
0,
|
||||||
|
i128::from(options.move_hue_cycle_ms) * 1_000_000,
|
||||||
|
now_ns,
|
||||||
|
)
|
||||||
|
.map(|(color, _, _)| (identity.clone(), [color.0, color.1, color.2]))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect::<Vec<_>>();
|
||||||
options
|
options
|
||||||
.move_marker_camera_sources
|
.move_marker_camera_sources
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -4278,6 +4294,7 @@ fn active_move_marker_camera_sources(options: &Options) -> Vec<ActiveMoveMarkerC
|
||||||
camera_index,
|
camera_index,
|
||||||
options.move_tracker_exposure_milli as f32 / 1000.0,
|
options.move_tracker_exposure_milli as f32 / 1000.0,
|
||||||
move_colors.clone(),
|
move_colors.clone(),
|
||||||
|
options.move_hue_cycle_ms,
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -4384,6 +4401,7 @@ fn start_psmoveapi_tracker_worker(
|
||||||
camera_index: i32,
|
camera_index: i32,
|
||||||
exposure: f32,
|
exposure: f32,
|
||||||
colors: Vec<(String, [u8; 3])>,
|
colors: Vec<(String, [u8; 3])>,
|
||||||
|
move_hue_cycle_ms: u64,
|
||||||
) -> mpsc::Receiver<Vec<muninn_psmoveapi_tracker::PsmoveApiObservation>> {
|
) -> mpsc::Receiver<Vec<muninn_psmoveapi_tracker::PsmoveApiObservation>> {
|
||||||
let (sender, receiver) = mpsc::sync_channel(1);
|
let (sender, receiver) = mpsc::sync_channel(1);
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
|
|
@ -4401,9 +4419,26 @@ fn start_psmoveapi_tracker_worker(
|
||||||
let mut last_calibration_at = Instant::now();
|
let mut last_calibration_at = Instant::now();
|
||||||
loop {
|
loop {
|
||||||
if last_calibration_at.elapsed() >= Duration::from_secs(30) {
|
if last_calibration_at.elapsed() >= Duration::from_secs(30) {
|
||||||
tracker.calibrate_connected();
|
tracker.observe_connected();
|
||||||
last_calibration_at = Instant::now();
|
last_calibration_at = Instant::now();
|
||||||
}
|
}
|
||||||
|
let mut roster = colors.iter().map(|(identity, _)| identity.clone()).collect::<Vec<_>>();
|
||||||
|
roster.sort();
|
||||||
|
let now_ns = SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.as_nanos() as i128;
|
||||||
|
for identity in &roster {
|
||||||
|
if let Some((color, _, _)) = scheduled_golden_move_color(
|
||||||
|
identity,
|
||||||
|
&roster,
|
||||||
|
0,
|
||||||
|
i128::from(move_hue_cycle_ms) * 1_000_000,
|
||||||
|
now_ns,
|
||||||
|
) {
|
||||||
|
tracker.set_expected_color(identity, [color.0, color.1, color.2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
let observations = tracker.update();
|
let observations = tracker.update();
|
||||||
match sender.try_send(observations) {
|
match sender.try_send(observations) {
|
||||||
Ok(()) | Err(mpsc::TrySendError::Full(_)) => {}
|
Ok(()) | Err(mpsc::TrySendError::Full(_)) => {}
|
||||||
|
|
|
||||||
|
|
@ -52,13 +52,20 @@ mod linux {
|
||||||
fn psmove_disconnect(controller: *mut c_void);
|
fn psmove_disconnect(controller: *mut c_void);
|
||||||
fn psmove_tracker_new_with_camera(camera: c_int) -> *mut c_void;
|
fn psmove_tracker_new_with_camera(camera: c_int) -> *mut c_void;
|
||||||
fn psmove_tracker_free(tracker: *mut c_void);
|
fn psmove_tracker_free(tracker: *mut c_void);
|
||||||
fn psmove_tracker_enable_with_color(
|
fn psmove_tracker_enable_color_observer(
|
||||||
tracker: *mut c_void,
|
tracker: *mut c_void,
|
||||||
controller: *mut c_void,
|
controller: *mut c_void,
|
||||||
red: c_uchar,
|
red: c_uchar,
|
||||||
green: c_uchar,
|
green: c_uchar,
|
||||||
blue: c_uchar,
|
blue: c_uchar,
|
||||||
) -> c_int;
|
) -> c_int;
|
||||||
|
fn psmove_tracker_set_expected_color(
|
||||||
|
tracker: *mut c_void,
|
||||||
|
controller: *mut c_void,
|
||||||
|
red: c_uchar,
|
||||||
|
green: c_uchar,
|
||||||
|
blue: c_uchar,
|
||||||
|
) -> bool;
|
||||||
fn psmove_tracker_disable(tracker: *mut c_void, controller: *mut c_void);
|
fn psmove_tracker_disable(tracker: *mut c_void, controller: *mut c_void);
|
||||||
fn psmove_tracker_set_exposure(tracker: *mut c_void, exposure: c_float);
|
fn psmove_tracker_set_exposure(tracker: *mut c_void, exposure: c_float);
|
||||||
fn psmove_tracker_get_exposure(tracker: *mut c_void) -> c_float;
|
fn psmove_tracker_get_exposure(tracker: *mut c_void) -> c_float;
|
||||||
|
|
@ -117,7 +124,7 @@ mod linux {
|
||||||
exposure,
|
exposure,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
result.calibrate_connected();
|
result.observe_connected();
|
||||||
result.camera_info = unsafe {
|
result.camera_info = unsafe {
|
||||||
let info = psmove_tracker_get_camera_info(tracker);
|
let info = psmove_tracker_get_camera_info(tracker);
|
||||||
if info.is_null() {
|
if info.is_null() {
|
||||||
|
|
@ -139,6 +146,10 @@ mod linux {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calibrate_connected(&mut self) -> usize {
|
pub fn calibrate_connected(&mut self) -> usize {
|
||||||
|
self.observe_connected()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn observe_connected(&mut self) -> usize {
|
||||||
let count = unsafe { psmove_count_connected() }.max(0);
|
let count = unsafe { psmove_count_connected() }.max(0);
|
||||||
for index in 0..count {
|
for index in 0..count {
|
||||||
let handle = unsafe { psmove_connect_by_id(index) };
|
let handle = unsafe { psmove_connect_by_id(index) };
|
||||||
|
|
@ -158,7 +169,7 @@ mod linux {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let status = unsafe {
|
let status = unsafe {
|
||||||
psmove_tracker_enable_with_color(
|
psmove_tracker_enable_color_observer(
|
||||||
self.tracker, handle, color[0], color[1], color[2]
|
self.tracker, handle, color[0], color[1], color[2]
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
@ -172,6 +183,23 @@ mod linux {
|
||||||
self.controllers.len()
|
self.controllers.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_expected_color(&mut self, move_id: &str, color: [u8; 3]) -> bool {
|
||||||
|
let Some(controller) = self.controllers.iter().find(|controller| {
|
||||||
|
controller.move_id.eq_ignore_ascii_case(move_id)
|
||||||
|
}) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
psmove_tracker_set_expected_color(
|
||||||
|
self.tracker,
|
||||||
|
controller.handle,
|
||||||
|
color[0],
|
||||||
|
color[1],
|
||||||
|
color[2],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn camera_info(&self) -> &PsmoveApiCameraInfo {
|
pub fn camera_info(&self) -> &PsmoveApiCameraInfo {
|
||||||
&self.camera_info
|
&self.camera_info
|
||||||
}
|
}
|
||||||
|
|
@ -255,6 +283,10 @@ impl PsmoveApiTracker {
|
||||||
|
|
||||||
pub fn calibrate_connected(&mut self) -> usize { 0 }
|
pub fn calibrate_connected(&mut self) -> usize { 0 }
|
||||||
|
|
||||||
|
pub fn observe_connected(&mut self) -> usize { 0 }
|
||||||
|
|
||||||
|
pub fn set_expected_color(&mut self, _move_id: &str, _color: [u8; 3]) -> bool { false }
|
||||||
|
|
||||||
pub fn tracked_controller_count(&self) -> usize { 0 }
|
pub fn tracked_controller_count(&self) -> usize { 0 }
|
||||||
|
|
||||||
pub fn update(&mut self) -> Vec<PsmoveApiObservation> {
|
pub fn update(&mut self) -> Vec<PsmoveApiObservation> {
|
||||||
|
|
|
||||||
13
native/psmoveapi-muninn/README.md
Normal file
13
native/psmoveapi-muninn/README.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Muninn PSMoveAPI Observer Patch
|
||||||
|
|
||||||
|
Muninn owns PS Move LED output. PSMoveAPI owns camera exposure, HSV filtering,
|
||||||
|
morphology, contour extraction, and marker position estimation.
|
||||||
|
|
||||||
|
`expected-color-observer.patch` adds only the missing authority boundary:
|
||||||
|
|
||||||
|
- enable tracking without blinking or writing LEDs;
|
||||||
|
- update the expected camera hue without writing LEDs.
|
||||||
|
|
||||||
|
The expected hue comes from Muninn's timestamp-driven `gold(x)` schedule. This
|
||||||
|
patch must be applied to the pinned PSMoveAPI source with `git apply --recount`
|
||||||
|
before building the Nightwing tracker libraries.
|
||||||
83
native/psmoveapi-muninn/expected-color-observer.patch
Normal file
83
native/psmoveapi-muninn/expected-color-observer.patch
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
diff --git a/include/psmove_tracker.h b/include/psmove_tracker.h
|
||||||
|
index 7de998b..d44db20 100644
|
||||||
|
--- a/include/psmove_tracker.h
|
||||||
|
+++ b/include/psmove_tracker.h
|
||||||
|
@@ -235,6 +235,25 @@ ADDCALL psmove_tracker_get_auto_update_leds(PSMoveTracker *tracker, PSMove *move
|
||||||
|
ADDAPI void
|
||||||
|
ADDCALL psmove_tracker_set_exposure(PSMoveTracker *tracker, float exposure);
|
||||||
|
|
||||||
|
+/**
|
||||||
|
+ * Enable reference blob tracking without writing controller LEDs.
|
||||||
|
+ * The caller owns LED output and supplies the expected fully-saturated RGB hue.
|
||||||
|
+ */
|
||||||
|
+ADDAPI enum PSMoveTracker_Status
|
||||||
|
+ADDCALL psmove_tracker_enable_color_observer(PSMoveTracker *tracker, PSMove *move,
|
||||||
|
+ unsigned char r, unsigned char g, unsigned char b);
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * Change the expected RGB hue for an observer-enabled controller without
|
||||||
|
+ * writing controller LEDs or running blinking calibration.
|
||||||
|
+ */
|
||||||
|
+ADDAPI bool
|
||||||
|
+ADDCALL psmove_tracker_set_expected_color(PSMoveTracker *tracker, PSMove *move,
|
||||||
|
+ unsigned char r, unsigned char g, unsigned char b);
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* \brief Get exposure as fraction (0.0 -> 1.0)
|
||||||
|
**/
|
||||||
|
diff --git a/src/tracker/psmove_tracker.cpp b/src/tracker/psmove_tracker.cpp
|
||||||
|
index 23e33ed..621b9ea 100644
|
||||||
|
--- a/src/tracker/psmove_tracker.cpp
|
||||||
|
+++ b/src/tracker/psmove_tracker.cpp
|
||||||
|
@@ -547,6 +547,49 @@ psmove_tracker_get_exposure(PSMoveTracker *tracker)
|
||||||
|
return tracker->settings.camera_exposure;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void
|
||||||
|
+psmove_tracker_assign_observed_color(TrackedController *tc,
|
||||||
|
+ unsigned char r, unsigned char g, unsigned char b)
|
||||||
|
+{
|
||||||
|
+ struct PSMove_RGBValue rgb = { r, g, b };
|
||||||
|
+ CvScalar hsv = th_rgb2hsv(cvScalar(r, g, b, 255.0));
|
||||||
|
+ tc->color = rgb;
|
||||||
|
+ tc->auto_update_leds = false;
|
||||||
|
+ tc->eColorHSV = tc->eFColorHSV = hsv;
|
||||||
|
+ tc->assignedHSV = hsv;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+enum PSMoveTracker_Status
|
||||||
|
+psmove_tracker_enable_color_observer(PSMoveTracker *tracker, PSMove *move,
|
||||||
|
+ unsigned char r, unsigned char g, unsigned char b)
|
||||||
|
+{
|
||||||
|
+ psmove_return_val_if_fail(tracker != NULL, Tracker_CALIBRATION_ERROR);
|
||||||
|
+ psmove_return_val_if_fail(move != NULL, Tracker_CALIBRATION_ERROR);
|
||||||
|
+
|
||||||
|
+ TrackedController *tc = psmove_tracker_find_controller(tracker, move);
|
||||||
|
+ if (tc == NULL) {
|
||||||
|
+ tc = psmove_tracker_find_controller(tracker, NULL);
|
||||||
|
+ }
|
||||||
|
+ if (tc == NULL) {
|
||||||
|
+ return Tracker_CALIBRATION_ERROR;
|
||||||
|
+ }
|
||||||
|
+ tc->move = move;
|
||||||
|
+ psmove_tracker_assign_observed_color(tc, r, g, b);
|
||||||
|
+ return Tracker_CALIBRATED;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+bool
|
||||||
|
+psmove_tracker_set_expected_color(PSMoveTracker *tracker, PSMove *move,
|
||||||
|
+ unsigned char r, unsigned char g, unsigned char b)
|
||||||
|
+{
|
||||||
|
+ psmove_return_val_if_fail(tracker != NULL, false);
|
||||||
|
+ psmove_return_val_if_fail(move != NULL, false);
|
||||||
|
+ TrackedController *tc = psmove_tracker_find_controller(tracker, move);
|
||||||
|
+ if (tc == NULL) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ psmove_tracker_assign_observed_color(tc, r, g, b);
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void
|
||||||
|
psmove_tracker_reset_color_calibration(PSMoveTracker *tracker)
|
||||||
|
{
|
||||||
Loading…
Reference in a new issue