Into to SMMobility - iOS
  • 26 Feb 2024
  • 4 Minutes to read
  • Dark
    Light

Into to SMMobility - iOS

  • Dark
    Light

Article Summary


SMMobility is a 'core level' SDK which allows direct access to SencyMotion's mobility tests. Using this SDK you'll get full flexibility to create your own mobility session by simply implementing easy to use APIs, and build your own UI on top of it.

Installing SMMobility

Install via Cocoapods:

source 'https://bitbucket.org/sency-ios/sency_ios_sdk.git'
source 'https://github.com/CocoaPods/Specs.git'

target 'YourApp' do
  use_frameworks!
  pod 'SMMobility', '0.1.4'
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
      config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64'
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.5'
    end
  end
end


Configuring SMMobility

Configure the SDK on app launch:

import UIKit
import SMMobility

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        SMMobilityFlowManager.configure(authKey: "YOUR_AUTH_KEY") {
            // success
        } onFailure: { error in
            // failure
        }

        return true
    }
}

Call SMSessionManager to configure with your auth key. This process might take a few seconds and if you try to do anything else with SMMobility before it completes, you will receive an error.



Using SMMobility

Init SMMobilityFlowManager

First, init the SMMobilityFlowManager

class ViewController: UIViewController {
    var flowManager:SMMobilityFlowManager?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        //If Auth passes successfuly
        do{
            flowManager = try SMMobilityFlowManager(delegate: self)
        }catch{
            print(error)
        }
    }
}

extension ViewController:SMMobilitySessionDelegate{
    func captureSessionDidSet(session: AVCaptureSession) {
        //You can use this to present the camera output
    }

    func poseDataDidUpdate(poseData: [Joint : CGPoint]?) {
        //In here you will receive all the skeleton data
    }    
    
    func isChangingStepValid(step: _MobilityTestStep, nextStep: _MobilityTestStep) -> Bool {
        //In here you will receive the current step and the next step in the mobility state  machine. You will decide when to allow this change to happen by returning a boolean.
    }

   func triggerAlert(alert: MobilityAlert) {
        //In here you will get trigger to an alert from our alerting mechanism. 
    }

   func mobilityTestDidFinish(scores: [MobilityAssessmentResultData]?, error:Error?) {
         //In here you will receive an indication for finishing the mobility test
     }

    func setCompletePhoneCalibration() -> Bool {
          //In here you will receive an indication once the phone calibration is completed
      }

    func phoneCalStatusDidChange(inRange: Bool, phoneCalInfo: SMPhoneCalibrationInfo) {
           //In here you will receive an indication about the phone calibration status
      } 

    func defineBodyCalibrationRectangle(rect: MobilityBodyCalRectGuide) {
         //In here you will receive the desired body calibration rectangle  
     }

    func bodyCalStatusDidChange(inFrame: Bool) {
          //In here you will receive an indication if the person is in the frame
    }

    func handleSessionErrors(error: Error) {
          //In here you will receive any error raised in SMMobility SDK
    }
}

Make sure to conform to SMMobilitySessionDelegate:

  • captureSessionDidSet - Once the camera data is available this function will be called with a AVCaptureSession you then can use it to present the camera output
  • poseDataDidUpdate - This function will be called every frame with the following data:
    • poseData - This a dictionary of joints and there position (can be empty if the user was not detected in the camera field of view)
  • isChangingStateValid - This function will be called once the mobility logic requesting a change in it's state machine
    • Inputs - 
      • step  - current step (see _MobilityTestStep description below)
      • nextStep - the required next step (see _MobilityTestStep description below) 
    • Output -
      • Bool - should be true once allowing the step transition
  • triggerAlert- This function will be called once an Alert is raised
    • alert - see MobilityAlert description below
  • mobilityTestDidFinish - This function will be called once the mobility session has been completed
    • MobilityAssessmentResultData:
      • type (MobilityTestType) - .hamstring / .shoulders
      • side (Side) - .right / .left / .none
      • score (Float) - indicating the session score
      • bestPositionTime (Float) - indicating the time passed since the beginning of the measurement which achieved the highest score in the session
      • creationDate (Date) - indicating the time when the results were formed
  • setCompletePhoneCalibration - This function will be called once the phone calibration has been completed
  • phoneCalStatusDidChange - This function will be called once there is a change in the phone calibration status
    • inRange (Bool) - indicates if tilt angle are properly set
    • phoneCalInfo (SMPhoneCalibrationInfo) - contains the phone calibration configurations
  •  bodyCalStatusDidChange - This function will be called once there is a change in the body calibration status
    • inFrame (Bool) - indicated if the person is inside the defined rectangle
  • defineBodyCalibrationRectangle - This function will be called once test has been started
    • rect (MobilityBodyCalRectGuide) - indicates the desired rectangle for the mobility test
      • widthScale - defines the scale [0-1] from the video size (will be symmetric on the x-axis)
      • heightScale - defines the scale [0-1] from the video size (will be symmetric on the y-axis) 
      • originY - defines the beginning point [0-1] from the top left corner of the video size
_MobilityTestStep
Init - first step after initializing the SMMobilityFlowManager
PhoneCal - phone calibration step
BodyCal - body calibration step
PoseCal - detecting valid initial position
Start - detecting in position requirements
PreMeasure - making preparations for the measuring step
Measure - measuring test angle
OutOfPosition - detecting out of position in the middle of the measurement
Finished - finished mobility test

The state machine transitions is describes below:

MobilityAlert
// Hamstring Test
PoseHamstring0 - "Please side sideways to the camera"
PoseHamstring1 - "Straighten your legs"
PoseHamstring2 - "Make sure your legs are inside the frame boundaries"
PoseHamstring3 - "Reach forward with your hands"

// Shoulders Test
PoseShouldersOH0 - "Straighten your hands and keep your elbows locked"
PoseShouldersOH1 - "Lower your ribs"
PoseShouldersOH2 - "Raise your hands up"
PoseShouldersOH3 - "Straight your back"

Using SMMobility

func startTest(testType: MobilityTestType, activeSide: Side, phonePosition: PhonePosition){
    do{
        try flowManager?.startTest(testType: testType, activeSide: activeSide, phonePosition: phonePosition)
    }catch{
        print(error)
    }
 }
  • testType (MobilityTestType) - defines the desired test
    • hamstring test
    • shoulders test
  • activeSide (Side)- defines the close to the camera side
    • right (right body parts are closer to the camera)
    • left (left body parts are closer to the camera)
    • none (we choose this option when we are looking to the camera while performing the test)
  • phonePosition (PhonePosition) - defines the phone position
    • Elevated - phone is perpendicular to the floor and above the floor level
    • Floor - phone is on the floor and leaned on the wall or different object

Phone Calibration Observer

flowManager?.setDeviceMotionActive(
            phoneCalibrationInfo: SMPhoneCalibrationInfo(
            YZAngleRange: 63.0..<70.0,
            XYAngleRange: Float(-5.0)..<Float(5.0))
)


List of possible SMMobility errors

  • testTypeNotImplemented
  • couldNotSetCaptureSession
  • unableToCreateSummeryData
  • CameraIsAlreadyRunning
  • UnableToStartCamera
  • UnknoneErrorAccord




Was this article helpful?