Observe scheduled Move hues through PSMoveAPI
This commit is contained in:
parent
f7f8edf422
commit
e6a8002c4c
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> {
|
||||
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()
|
||||
.map(|source| {
|
||||
let (red, green, blue) = default_move_color_for_identity(&source.move_id);
|
||||
(source.move_id, [red, green, blue])
|
||||
.map(|source| source.move_id)
|
||||
.collect::<Vec<_>>();
|
||||
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
|
||||
.move_marker_camera_sources
|
||||
.iter()
|
||||
|
|
@ -4278,6 +4294,7 @@ fn active_move_marker_camera_sources(options: &Options) -> Vec<ActiveMoveMarkerC
|
|||
camera_index,
|
||||
options.move_tracker_exposure_milli as f32 / 1000.0,
|
||||
move_colors.clone(),
|
||||
options.move_hue_cycle_ms,
|
||||
))
|
||||
})
|
||||
} else {
|
||||
|
|
@ -4384,6 +4401,7 @@ fn start_psmoveapi_tracker_worker(
|
|||
camera_index: i32,
|
||||
exposure: f32,
|
||||
colors: Vec<(String, [u8; 3])>,
|
||||
move_hue_cycle_ms: u64,
|
||||
) -> mpsc::Receiver<Vec<muninn_psmoveapi_tracker::PsmoveApiObservation>> {
|
||||
let (sender, receiver) = mpsc::sync_channel(1);
|
||||
thread::spawn(move || {
|
||||
|
|
@ -4401,9 +4419,26 @@ fn start_psmoveapi_tracker_worker(
|
|||
let mut last_calibration_at = Instant::now();
|
||||
loop {
|
||||
if last_calibration_at.elapsed() >= Duration::from_secs(30) {
|
||||
tracker.calibrate_connected();
|
||||
tracker.observe_connected();
|
||||
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();
|
||||
match sender.try_send(observations) {
|
||||
Ok(()) | Err(mpsc::TrySendError::Full(_)) => {}
|
||||
|
|
|
|||
|
|
@ -52,13 +52,20 @@ mod linux {
|
|||
fn psmove_disconnect(controller: *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_enable_with_color(
|
||||
fn psmove_tracker_enable_color_observer(
|
||||
tracker: *mut c_void,
|
||||
controller: *mut c_void,
|
||||
red: c_uchar,
|
||||
green: c_uchar,
|
||||
blue: c_uchar,
|
||||
) -> 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_set_exposure(tracker: *mut c_void, exposure: c_float);
|
||||
fn psmove_tracker_get_exposure(tracker: *mut c_void) -> c_float;
|
||||
|
|
@ -117,7 +124,7 @@ mod linux {
|
|||
exposure,
|
||||
},
|
||||
};
|
||||
result.calibrate_connected();
|
||||
result.observe_connected();
|
||||
result.camera_info = unsafe {
|
||||
let info = psmove_tracker_get_camera_info(tracker);
|
||||
if info.is_null() {
|
||||
|
|
@ -139,6 +146,10 @@ mod linux {
|
|||
}
|
||||
|
||||
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);
|
||||
for index in 0..count {
|
||||
let handle = unsafe { psmove_connect_by_id(index) };
|
||||
|
|
@ -158,7 +169,7 @@ mod linux {
|
|||
continue;
|
||||
};
|
||||
let status = unsafe {
|
||||
psmove_tracker_enable_with_color(
|
||||
psmove_tracker_enable_color_observer(
|
||||
self.tracker, handle, color[0], color[1], color[2]
|
||||
)
|
||||
};
|
||||
|
|
@ -172,6 +183,23 @@ mod linux {
|
|||
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 {
|
||||
&self.camera_info
|
||||
}
|
||||
|
|
@ -255,6 +283,10 @@ impl PsmoveApiTracker {
|
|||
|
||||
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 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