Ниже я поделюсь кодом, который я использовал для сбора данных акселерометра и гироскопа.
Во-первых, этот класс отвечает за процесс сбора:
Код: Выделить всё
class SensorCollector: ObservableObject {
private let motionManager = CMMotionManager()
private let sensorQueue = OperationQueue()
var accBuffer: [VibrateView.SensorReading] = []
var gyrBuffer: [VibrateView.SensorReading] = []
init() {
sensorQueue.name = "SensorCollectionQueue"
sensorQueue.qualityOfService = .userInitiated
}
func startSensors(startTime: TimeInterval) {
// 1. Clear buffers
accBuffer.removeAll(keepingCapacity: true)
gyrBuffer.removeAll(keepingCapacity: true)
// 2. Set Interval (sampling rate)
let interval = 0.0025
motionManager.accelerometerUpdateInterval = interval
motionManager.gyroUpdateInterval = interval
// 3. Start Updates on BACKGROUND QUEUE
if motionManager.isAccelerometerAvailable {
motionManager.startAccelerometerUpdates(to: sensorQueue) { [weak self] data, error in
guard let self = self, let data = data else { return }
let reading = VibrateView.SensorReading(
x: data.acceleration.x,
y: data.acceleration.y,
z: data.acceleration.z,
timestamp: data.timestamp - startTime
)
self.accBuffer.append(reading)
}
}
if motionManager.isGyroAvailable {
motionManager.startGyroUpdates(to: sensorQueue) { [weak self] data, error in
guard let self = self, let data = data else { return }
let reading = VibrateView.SensorReading(
x: data.rotationRate.x,
y: data.rotationRate.y,
z: data.rotationRate.z,
timestamp: data.timestamp - startTime
)
self.gyrBuffer.append(reading)
}
}
}
func stopSensors() {
motionManager.stopAccelerometerUpdates()
motionManager.stopGyroUpdates()
}
// Check availability
var isAccelAvailable: Bool { motionManager.isAccelerometerAvailable }
var isGyroAvailable: Bool { motionManager.isGyroAvailable }
}
Код: Выделить всё
struct VibrationEvent {
let time: TimeInterval
let duration: TimeInterval
let intensity: Float
}
func vibrateDevice(forTest test: String) async throws {
var events = [CHHapticEvent]()
let traceDuration: TimeInterval = 2.0
let currentTime: TimeInterval = 0
var someEvents: [VibrationEvent] = []
let test1: [VibrationEvent] = [
VibrationEvent(time: currentTime, duration: 2.0, intensity: 1.0)
]
let test2: [VibrationEvent] = [
VibrationEvent(time: currentTime, duration: 0.5, intensity: 0.8),
VibrationEvent(time: currentTime + 0.5, duration: 0.5, intensity: 0.9),
VibrationEvent(time: currentTime + 1.0, duration: 0.5, intensity: 1.0),
VibrationEvent(time: currentTime + 1.5, duration: 0.5, intensity: 1.0)
]
let test3: [VibrationEvent] = [
VibrationEvent(time: currentTime, duration: 0.4, intensity: 1.0),
VibrationEvent(time: currentTime + 0.8, duration: 0.4, intensity: 1.0),
VibrationEvent(time: currentTime + 1.6, duration: 0.4, intensity: 1.0)
]
let test4: [VibrationEvent] = [
VibrationEvent(time: currentTime, duration: 0.4, intensity: 0.8),
VibrationEvent(time: currentTime + 0.8, duration: 0.4, intensity: 0.9),
VibrationEvent(time: currentTime + 1.6, duration: 0.4, intensity: 1.0)
]
let test5: [VibrationEvent] = [
VibrationEvent(time: currentTime, duration: 0.25, intensity: 1.0),
VibrationEvent(time: currentTime + 0.25, duration: 0.25, intensity: 0.2),
VibrationEvent(time: currentTime + 0.50, duration: 0.25, intensity: 1.0),
VibrationEvent(time: currentTime + 0.75, duration: 0.25, intensity: 0.2),
VibrationEvent(time: currentTime + 1.00, duration: 0.25, intensity: 1.0),
VibrationEvent(time: currentTime + 1.25, duration: 0.25, intensity: 0.2),
VibrationEvent(time: currentTime + 1.50, duration: 0.25, intensity: 1.0),
VibrationEvent(time: currentTime + 1.75, duration: 0.25, intensity: 0.2)
]
let test6: [VibrationEvent] = [
VibrationEvent(time: currentTime, duration: 0.4, intensity: 0.6),
VibrationEvent(time: currentTime + 0.4, duration: 0.4, intensity: 0.7),
VibrationEvent(time: currentTime + 0.8, duration: 0.4, intensity: 0.8),
VibrationEvent(time: currentTime + 1.2, duration: 0.4, intensity: 0.9),
VibrationEvent(time: currentTime + 1.6, duration: 0.4, intensity: 1.0)
]
if selectedTest.contains("Test 1"){
someEvents = test1
} else if selectedTest.contains("Test 2") {
someEvents = test2
} else if selectedTest.contains("Test 3") {
someEvents = test3
} else if selectedTest.contains("Test 4") {
someEvents = test4
} else if selectedTest.contains("Test 5") {
someEvents = test5
} else if selectedTest.contains("Test 6"){
someEvents = test6
}
for event in someEvents {
events.append(addVibration(at: event.time, duration: event.duration, intensity: event.intensity))
}
do {
let pattern = try CHHapticPattern(events: events, parameters: [])
let player = try engine?.makePlayer(with: pattern)
try player?.start(atTime: 0)
} catch {
print("Failed to play pattern: \(error.localizedDescription)")
}
let totalDuration = (someEvents.map { $0.time + $0.duration }.max() ?? 0)
try await Task.sleep(nanoseconds: UInt64(totalDuration * 1_000_000_000))
}
Код: Выделить всё
func startVibrationTest() async {
// 1. UI Setup
testRunning = true
canClearResults = false
tracesData = []
testStartTime = currentUptimeSeconds()
do {
try await prepareHaptics()
// MARK: - SCENARIO A: Test 0 (Rest Only)
if selectedTest.contains("Test 0") {
let restDuration: TimeInterval = 10.0
let restStart = currentUptimeSeconds()
// A. Start Collecting
collector.startSensors(startTime: currentUptimeSeconds())
// B. Wait
try await Task.sleep(nanoseconds: UInt64(restDuration * 1_000_000_000))
// C. Stop Collecting
collector.stopSensors()
// D. Save Data
let restTrace = TraceReadings(
id: 1,
accelerometer: collector.accBuffer,
gyroscope: collector.gyrBuffer,
startTime: restStart,
endTime: currentUptimeSeconds(),
traceType: .rest
)
// Append to array (UI Update on Main Actor)
await MainActor.run {
tracesData.append(restTrace)
}
sendDataToServer()
}
// MARK: - SCENARIO B: Vibration Tests (1-6)
else {
let numberOfTraces = 10
let breakDuration: TimeInterval = 10.0
for traceIndex in 0..
Подробнее здесь: [url]https://stackoverflow.com/questions/79883592/detecting-vibrations-from-internal-vibration-motor-using-accelerometer[/url]