Intro to SMFit - iOS
  • 26 Feb 2024
  • 3 Minutes to read
  • Dark
    Light

Intro to SMFit - iOS

  • Dark
    Light

Article Summary

SMFit is a 'core level' SDK which allows direct access to SencyMotion's fitness domain functionalities and features. Using this SDK you'll get full flexibility to create your own workout structures by simply implementing easy to use APIs, and build your own UI on top of it.

Article work in progress
This article is still under writing stages. More updates about additional functionalities existing in SMFit will be published soon.



Installing SMFit

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 'SMFit', '0.2.0'
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 SMFit

Configure the SDK on app launch:

import UIKit
import SMFit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
       SMExerciseFlowManager.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 SMFit before it completes, you will receive an error.

First app open
Note that on first app open (first time launch) this process may take longer than usual.


Using SMFit

InitSMExerciseFlowManager

First, init the SMExerciseFlowManager

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

extension ViewController:SMFitSessionDelegate{
    func captureSessionDidSet(session: AVCaptureSession) {
        //You can use this to present the camera output
    }
    
    func captureSessionDidStop() {
        //If the camera session stops this function will be called
    }
    
    func handleDetectionData(movementData: MovementFeedbackData?) {
        //In here you will receive all of the detection data
    }

    func handlePositionData(poseData: [Joint : CGPoint]?) {
        
    }    

    func handleSessionErrors(error: Error) {
        print("handleSessionErrors: ", error)
    }
}

Make sure to conform to SMFitSessionDelegate:

  • 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
  • captureSessionDidStop - If the camera session stops this function will be called
  • handleDetectionData- This function will be called every frame with the following data:
    • MovementFeedbackResultData- This struct holds all the feedback data
      • didDetectRep - (Dynamic exercise) If user did perform repetition
      • isGoodRep - (Dynamic exercise) true if the repetition was good
      • isInPosition - (Static/Isometric exercise type) true if the user in position
      • currentRomValue - The current Range Of Motion of the user
      •  specialParams - some dynamic exercises will have some special params for example the exercise "Jumps" has "JumpPeakHeight" and "currHeight"
  • handlePositionData -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)

Start the exercise session

Initiate the session:

func startSession(){
    do{
        try flowManager?.startSession()
    }catch{
        print(error)
    }
 }

Start detection:

func startDetection(){
    do{
        try flowManager?.startDetection(exercise: "HighKnees")
    }catch{
        print(error)
    }
}

Go to Sency's exercise library to view the currently supported exercise types

Stop detection:

func stopDetection(){
    do{
        let exerciseSummary = try flowManager?.stopDetection()
    }catch{
        print(error)
    }
}

When you stop exercise detection you will get all detected data packed in a struct of type SMExerciseInfo:

  • sessionId - current session Id
  • startTime - the exercise start time
  • endTime - the exercise end time
  • totalTime- time in seconds from start to end detection

In addition you will get different data according to the type of the workout:

  • SMExerciseDynamicInfo
    • numberOfPerformedReps - the number of the performed reps
    • repsTechniqueScore - the exercise score
    • performedReps - array of RepData
  • SMExerciseStaticInfo
    • timeInActiveZone - time the user was in position
    • positionTechniqueScore - the exercise score

Stop session:

func stopSession(){
    let allSummary = flowManager?.stopSession()
}

When you stop session detection you will getall of the session's detected data packed in a struct of type DetectionSessionResultData which is the summary of the entire session:

  • exercises - all SMExerciseInfo of the session
  • startDate - the start date of the session
  • endData - the end date of the session

Calibration observers

Device motion observer:

flowManager?.setDeviceMotionActive(
            phoneCalibrationInfo: SMPhoneCalibrationInfo(
            YZAngleRange: 63.0..<70.0,
            XYAngleRange: Float(-5.0)..<Float(5.0)
        ),tiltDidChange: { (tiltInfo) in
            // handle tilt data
        })


Body positioning observer:

flowManager?.setBodyPositionCalibrationActive(delegate: self, screenSize: self.view.frame, boundingBox: rect)
extension ViewController:SMBodyCalibrationDelegate{
    func didEnterFrame() {
        // indicates the user is positioned 'inside' the 'rect' defined in "setBodyPositionCalibrationActive"
    }
    
    func didLeaveFrame() {
        // indicates the user is positioned 'outside' the 'rect' defined in "setBodyPositionCalibrationActive"
    }
    
    func didRecivedBoundingBox(box:CGRect){
        // since 'boundingBox' is optional in "setBodyPositionCalibrationActive", you will get the default 'rect' if you haven't added this argument
    }
}

List of possible SMFit errors

  • AuthKeyNotAccepted
  • UnableToGetNNModels
  • FailedLoadingNNModel
  • DidNotFindModelPath
  • CouldNotGetVisionRequest
  • ROMModelNoImplementationError
  • FailedToInitDetector
  • IllegalJumpThreshold
  • NNModelTypeNoImplementationError
  • NNModelMissingLocalUrl
  • CameraIsAlreadyRunning
  • DetectionAlreadyRunning
  • NoDetectionSessionRunning
  • UnableToStartCamera
  • UnexpectedCameraError

Was this article helpful?