UNPKG

react-native-guided-camera

Version:

A React Native component for agricultural camera guidance with sensor-based motion detection, orientation tracking, and real-time feedback.

183 lines 6.17 kB
import { Magnetometer } from "expo-sensors"; export class YawDetector { constructor(onYawChange, config = {}) { this.subscription = null; this.isActive = false; this.smoothedYaw = 0; this.targetYaw = null; this.onYawChange = onYawChange; this.config = { updateInterval: 10, yawTolerance: 10, // 8 degrees tolerance (more practical) smoothingFactor: 0.8, ...config, }; } calculateYaw(x, y) { let yaw = Math.atan2(y, x) * (180 / Math.PI); // Normalize to 0-360 degrees if (yaw < 0) yaw += 360; return yaw; } calculateYawMetrics(currentYaw) { let deviation = 0; let isOnTarget = true; let direction = "on_target"; let severity = "good"; // If no target is set, use the first reading as the target if (this.targetYaw === null) { this.targetYaw = currentYaw; console.log("YawDetector: Auto-setting target yaw to:", this.targetYaw); } // Calculate shortest angular distance (handling 360° wraparound) let diff = currentYaw - this.targetYaw; if (diff > 180) diff -= 360; if (diff < -180) diff += 360; deviation = Math.abs(diff); isOnTarget = deviation <= this.config.yawTolerance; if (!isOnTarget) { direction = diff > 0 ? "turn_left" : "turn_right"; if (deviation <= 15) { severity = "minor"; } else if (deviation <= 30) { severity = "major"; } else { severity = "major"; } } return { yaw: currentYaw, isOnTarget, deviation, direction, severity, }; } async start() { if (this.isActive) return; try { console.log("YawDetector: Requesting magnetometer permissions..."); const { status } = await Magnetometer.requestPermissionsAsync(); console.log("YawDetector: Permission status:", status); if (status !== "granted") { console.warn("YawDetector: Magnetometer permission not granted"); return; } console.log("YawDetector: Setting update interval to", this.config.updateInterval); Magnetometer.setUpdateInterval(this.config.updateInterval); console.log("YawDetector: Adding magnetometer listener..."); this.subscription = Magnetometer.addListener((data) => { const rawYaw = this.calculateYaw(data.x, data.y); // Apply smoothing if (this.smoothedYaw === 0) { this.smoothedYaw = rawYaw; } else { // Handle 360° wraparound for smoothing let diff = rawYaw - this.smoothedYaw; if (diff > 180) diff -= 360; if (diff < -180) diff += 360; this.smoothedYaw += diff * (1 - this.config.smoothingFactor); if (this.smoothedYaw < 0) this.smoothedYaw += 360; if (this.smoothedYaw >= 360) this.smoothedYaw -= 360; } const metrics = this.calculateYawMetrics(this.smoothedYaw); // console.log( // "YawDetector: Current:", // this.smoothedYaw.toFixed(1), // "Target:", // this.targetYaw?.toFixed(1), // "Deviation:", // metrics.deviation.toFixed(1), // "OnTarget:", // metrics.isOnTarget // ); this.onYawChange(metrics); }); this.isActive = true; console.log("YawDetector: Successfully started"); } catch (error) { console.error("YawDetector: Failed to start yaw detector:", error); } } stop() { if (this.subscription) { this.subscription.remove(); this.subscription = null; } this.isActive = false; } setTarget(yaw) { this.targetYaw = yaw; console.log("YawDetector: Target yaw set to:", yaw); } clearTarget() { this.targetYaw = null; console.log("YawDetector: Target yaw cleared"); } calibrateToCurrentPosition() { this.targetYaw = this.smoothedYaw; console.log("YawDetector: Calibrated target to current position:", this.targetYaw); } getCurrentYaw() { return this.smoothedYaw; } hasTarget() { return this.targetYaw !== null; } } // Helper functions for UI export const getYawColor = (severity) => { switch (severity) { case "good": return "#4CAF5070"; case "minor": return "#FF980070"; case "major": return "#F4433670"; default: return "#FF980070"; } }; export const getYawMessage = (metrics) => { if (metrics.isOnTarget) { return "Compass aligned"; } switch (metrics.direction) { case "turn_left": return "Turn body left"; case "turn_right": return "Turn body right"; default: return "Adjust orientation"; } }; // Translation-aware version export const getYawMessageTranslated = (metrics, translations) => { if (metrics.isOnTarget) { return translations.compassAligned; } switch (metrics.direction) { case "turn_left": return translations.turnBodyLeft; case "turn_right": return translations.turnBodyRight; default: return translations.adjustOrientation; } }; export const shouldAllowRecordingYaw = (metrics) => { return metrics.isOnTarget || metrics.severity === "minor"; }; //# sourceMappingURL=yawDetector.js.map