Motion Capture
UJT contains an Inertial Measurement Unit (IMU) sensor that consists of an accelerometer and gyroscope. With this feature, you can record, view and download your tag’s IMU sensor data. Accelerometer data consits of a vector (x, y, z) data, and Gyroscope has vector (yaw, pitch, roll) data.
This section will guide you to record, download, parse, erase IMU session. If you want the tag should collect IMU samples, loadable module must be activated. Note that activating IMU Module, will disable Wake on Motion(WoM) on the tag and you will also notice the tag battery draining considerably quickly.
1. Instantiate
You can create instance of ImuModule
using ConnectedJacquardTag
as below -
let imuModule = IMUModuleImplementation(connectedTag: tag)
2. Initialize
This is a mandatory step before you start recording IMU samples. There are multiple steps performed during initialize process.
Calling Initialize for the first time will load the Data Collection Loadable module(DCLM) on the device.
This process will be similar to Firmware Updating and will only be done once. ImuModule
will perform device firmware update(DFU) to download DCLM binary from cloud and send it to the tag. Once DFU is successful, ImuModule
will activate the DCLM to finish initialize process.
imuModule.initialize().sink { result in
switch result {
case .failure(let error):
print("IMU initialize error: \(error)")
case .finished:
break
}
} receiveValue: {
print("IMU initialized")
// After initialize, it's good practice to call `imuModule.checkStatus()`, to see if Tag is ready to record.
}
3. Start & stop IMU recording.
You can start collecting IMU samples by calling imuModule.startRecording(sessionID:)
api.
Provide a unique SessionID, less than 30 characters. It is a good practice to simply pass in the timestamp so that the SessionID is unique.
Similarly Call imuModule.stopRecording()
to end current IMU session.
imuModule.startRecording(sessionID: timestamp)
.sink { result in
switch result {
case .failure(let error):
print("Could not start IMUSession: \(error)")
case .finished:
break
}
} receiveValue: { status in
switch status {
case .logging:
// Indicates the recording has started.
case .lowBattery:
// Indicates the tag battery is not enough to start recording. Minimum battery should be 50%.
case .lowMemory:
// Indicates the tag storage is not enough to start recording.
default:
break
}
}
Note
An important point to remember here is that - you should not attach/detach the tag from gear during IMU session.
Which means - while starting a new IMU session whichever is the gear state, either attached or detached, must be same till you call stopImuSession()
api.
4. Fetch IMU session list
Calling this api will return each session individually, receiveValue for the publisher will be called everytime a session is received.
// Call listSessions api and sink immediately on the returned publisher to observe IMUSessions.
imuModule.listSessions().sink { result in
switch result {
case .failure(let error):
print("List Sessions error: \(error)")
case .finished:
break
}
} receiveValue: { [weak self] sessionInfo in
// Hold the sessionInfo objects.
guard let self = self else { return }
self.imuSessions.append(session)
}
5. Download IMU session
Calling listSessions() only fetches the metadata for the recorded sessions on the tag, Once the metadata is fetched, you can download the actual session file, using below code.
The apis gives you download progress and file path where IMU session data will be saved. As tag has
limited storage, to free up the space, The Jacquard SDK will erase the session file from Tag once download is complete.
It is highly recommended to move the file to another directory for further use. If there is an active IMU session on the tag, you can’t call
this api. To cancel ongoing download, you can simply call imuModule.stopDownloading()
.
imuModule.downloadIMUSessionData(session: session)
.sink { completion in
switch completion {
case .finished:
print("IMU file downloaded.")
case .failure(let error):
print("failed to download IMU file: \(error)")
}
} receiveValue: { [weak self] downloadState in
guard let self = self else { return }
switch downloadState {
case .downloading(let progress):
print("IMU downloading... \(progress)%")
case .downloaded(let filePath):
print("IMU state downloaded IMU file \(filePath)")
// Copy file locally to another folder.
}
@unknown default:
preconditionFailure("switch case not implemented.")
}
}
6. Erase IMU session(s)
You can either choose to delete a specific IMU session or all sessions from the tag.
imuModule.eraseSession(session: sessionInfo)
OR
imuModule.eraseAllSessions()
7. Parse IMU session data
Once you download the IMU session to the mobile device, You can view the IMU samples by parsing the session file. You can pass the downloaded session file path to below api to parse IMU session. It will return an IMUSessionData
object that will contain the vector data for accelerometer and gyroscope.
imuModule.parseIMUSession(path: filePath)
8. Get Data Collection status
To know the current data collection status of the tag, use below code -
imuModule.checkStatus()
The different states a tag could be in, are specified below.
enum DataCollectionStatus {
/// No logging in progress.
case idle
/// Session recording in progress.
case logging
/// Session data transfer in progress.
case dataTransferInProgress
/// Erasing session data in progress.
case erasingData
/// Not sufficient storage to start logging.
case lowMemory
/// Not sufficient battery to start logging. Minimum battery should be 50%.
case lowBattery
/// Error state.
case error
}
If DataCollectionStatus
is .idle
means the tag is ready to record new sessions.
9. Deactivate Data Collection Loadable Module
When you no longer require IMUModule
, it is advisable to deactivate the data collection module to save the tag battery.
imuModule.deactivateModule()