Getting Started
Install Dependencies
Install Dependencies:
- Xcode 14.2+
- Android Studio 2022.1.1+
- Node 18+
Build the Demo App
- Download and unzip the Rogue Vision SDK bundle. This is a zip file provided to you by Rogue.
unzip rogue-vision-sdk-latest.zip
- Install mobile app dependencies
cd rogue-vision-react-native-demo
yarn
npx pod-install
- Build for iOS
yarn start # starts React Native / Metro
yarn run ios
- Build for Android
yarn start # starts React Native / Metro
yarn run android
note
Make sure your Node binary is accesible to xcode and your shell.
BEFORE YOU RUN IN IOS:
echo "export NODE_BINARY=$(which node)" >> rogue-vision-demo/ios/.xcode.env
ON MAC ARM64 (M1/M2)
sudo ln -s $(which node) /usr/local/bin/node
Integrating into Your Own App
The React Native Demo provides a valid configuration that you can use to design your custom app integration.
note
The Movement Library and the SDK Library are two distinct libraries. It is possible to dynamically load models or to update the Model Library independent of the rest of the app.
Install Dependencies
yarn add react-native-vision-camera@2.x react-native-event-listeners xstate
yarn add @moonlight-labs/rogue-vision-react-native-sdk @moonlight-labs/rogue-vision-movements
Update your application manifest for camera permissions.
Update Configuration to Access SDK Events
// babel.config.js
module.exports = {
...,
plugins: [
[
'react-native-reanimated/plugin',
{
globals: ['__scanPoses', '__scanEquipment']
},
],
]
}
Import SDK Into App Code
import { EventRegister } from 'react-native-event-listeners'
import { Movements } from '@moonlight-labs/rogue-vision-movements'
import {
scanPoses,
scanEquipment,
countReps,
} from '@moonlight-labs/rogue-vision-react-native-sdk'
Enumerate the available models
<ul style={{ columns: 4 }}>
{Movements.all.map((movement) => (
<li>
<strong>{movement.name}</strong>
</li>
))}
</ul>
Start the camera and begin with specific models
function App() {
const selectedMovements = Movements.all.map((movement) => {
return movement
})
// Initialize all the selected movements reps to zero
const [repCount, setCount] = useState(
selectedMovements.reduce(function (map, movement) {
map[movement] = 0
return map
}, {})
)
const repCounter = useFrameProcessor((frame) => {
'worklet'
try {
const inputs = {
pose: scanPoses(frame),
equipment: scanEquipment(frame),
}
// non-blocking, runs async
runOnJS(countReps)(inputs, selectedMovements)
} catch (e) {
console.log(`Error: ${e.message}`)
}
}, [])
useEffect(() => {
// this handles the functionality for emitting rep messages
EventRegister.addEventListener('FrameProcessed', (repData) => {
// EXPECTED RESULTS
// [
// { type: 'pushups', 'repCount': 1, 'noRepCount': 0, 'queueNoRepCount': 0, event: RepCompleted }
// { type: 'squats', 'repCount': 0, 'noRepCount': 1, 'queueNoRepCount': 0, event: NoRep }
// ]
repData.map((message, index) => {
if (message.event == RepEventType.RepCompleted) {
// increment the rep count for the detected movement
const newRepCount = message.repCount
newRepcount[message.type] = repcount
setCount(newRepCount)
// update the pose Display
if (Settings.SHOW_POSE_OVERLAY) updatePose(frameResult.pose)
} else if (repEvent.event == RepEventType.NoRep) {
console.log('No rep')
}
})
})
}, [])
return (
<Camera
frameProcessor={repCounter}
frameProcessorFps={60}
{...cameraProps}
/>
)
}