跳到主要内容AR 健身教练实践:基于 Rokid CXR-M SDK 的落地方案 | 极客日志KotlinAIjava算法
AR 健身教练实践:基于 Rokid CXR-M SDK 的落地方案
综述由AI生成基于 Rokid CXR-M SDK 构建 AR 健身应用,解决居家健身缺乏指导与沉浸感不足的痛点。项目采用分层架构,整合 Android 端应用与眼镜端硬件,利用 AI 场景实现实时动作识别与纠正,通过自定义页面渲染 AR 教练界面及数据可视化。关键技术点包括蓝牙设备连接、动态权限管理、JSON 布局渲染及低功耗策略。实践表明该方案能有效提升运动规范性与用户体验,为 AR+AI 健康场景提供了可落地的参考路径。
游戏玩家4 浏览 项目背景与创意起源
居家健身时,缺乏专业指导导致动作不规范甚至受伤是常见痛点。低头看手机或平板也会打断沉浸感。Rokid Glasses 的'抬头即见'交互方式恰好能解决这些问题。通过 Rokid CXR-M SDK 的 AI 场景、自定义页面和提词器功能,我们将专业教练'投射'到用户视野中,实现实时指导和数据反馈。


SDK 开发配置
CXR-M SDK 是面向移动端的开发工具包,用于构建手机端与 Rokid Glasses 的协同应用。目前仅提供 Android 版本。
Maven 仓库配置
在 settings.gradle.kts 的 dependencyResolutionManagement 节点中添加 Maven 仓库地址:https://maven.rokid.com/repository/maven-public/。
依赖导入
在 build.gradle.kts 的 dependencies 节点添加 SDK Package:com.rokid.cxr:client-m:1.0.1-20250812.080117-2。注意 SDK 要求 minSdk≥28,若与项目现有版本冲突,优先选用 SDK 对应版本。
权限申请
SDK 需要网络、Wi-Fi 及蓝牙权限(蓝牙需同步申请 FINE_LOCATION)。在 AndroidManifest.xml 中声明最小权限集:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name= />
"android.permission.BLUETOOTH"
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
使用前务必进行动态权限申请,否则 SDK 将不可用。示例代码如下:
class MainActivity : AppCompatActivity() {
companion object {
const val TAG = "MainActivity"
const val REQUEST_CODE_PERMISSIONS = 100
private val REQUIRED_PERMISSIONS = mutableListOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN,
).apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
add(Manifest.permission.BLUETOOTH_SCAN)
add(Manifest.permission.BLUETOOTH_CONNECT)
}
}.toTypedArray()
}
private val permissionGrantedResult = MutableLiveData<Boolean?>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
permissionGrantedResult.postValue(null)
requestPermissions(REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
permissionGrantedResult.observe(this) { granted ->
if (granted == true) {
} else {
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_CODE_PERMISSIONS.hashCode()) {
val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
permissionGrantedResult.postValue(allGranted)
}
}
}
技术架构设计
应用层(Android App) → CXR-M SDK → Rokid Glasses(YodaOS) → 硬件传感器
- 应用层:提供 UI、健身计划管理、社交功能。
- CXR-M SDK:负责通信、AI 场景处理、AR 界面渲染。
- Rokid Glasses:执行 AR 渲染、动作捕捉、数据反馈。
- 硬件传感器:提供姿态、心率等原始数据。
核心组件包括实时动作识别、个性化计划、AR 教练界面、数据可视化及社交互动模块。各组件通过 SDK 接口通信,业务逻辑与硬件交互完全分离。
关键功能实现
设备连接与初始化
一切始于稳定的设备连接。我们需要扫描并连接 Rokid 设备,随后初始化 AI 场景。
class FitnessApp : AppCompatActivity() {
private val REQUIRED_PERMISSIONS =
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (!hasPermissions(REQUIRED_PERMISSIONS)) {
requestPermissions(REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
} else {
initializeDeviceConnection()
}
}
private fun initializeDeviceConnection() {
val scanner = BluetoothLeScannerCompat.getScanner()
scanner.startScan(
listOf(ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString("00009100-0000-1000-8000-00805f9b34fb"))
.build()),
ScanSettings.Builder().build(),
scanCallback
)
}
private val scanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
val device = result.device
CxrApi.getInstance().initBluetooth(this@FitnessApp, device, object : BluetoothStatusCallback {
override fun onConnectionInfo(socketUuid: String?, macAddress: String?, rokidAccount: String?, glassesType: Int) {
Log.d("FitnessApp", "Connection info: $socketUuid")
CxrApi.getInstance().connectBluetooth(this@FitnessApp, socketUuid, macAddress, this@FitnessApp)
}
override fun onConnected() {
Log.d("FitnessApp", "Bluetooth connected successfully")
initializeAiScene()
}
override fun onDisconnected() {
Log.e("FitnessApp", "Bluetooth disconnected")
}
override fun onFailed(errorCode: ValueUtil.CxrBluetoothErrorCode?) {
Log.e("FitnessApp", "Bluetooth connection failed: $errorCode")
}
})
}
}
private fun initializeAiScene() {
CxrApi.getInstance().setAiEventListener(object : AiEventListener {
override fun onAiEvent(eventType: ValueUtil.CxrAiEventType?, data: String?) {
when (eventType) {
ValueUtil.CxrAiEventType.ACTION_RECOGNITION -> handleActionRecognition(data)
}
}
})
CxrApi.getInstance().controlScene(ValueUtil.CxrSceneType.AI_SCENE, true, null)
}
}
实时动作捕捉与纠正
利用摄像头和 AI 能力实时分析动作质量。当识别结果低于阈值时,通过提词器显示纠正信息。
private fun startExercise(exerciseType: String) {
val actionParams = HashMap<String, String>()
actionParams["exerciseType"] = exerciseType
actionParams["threshold"] = "0.85"
CxrApi.getInstance().controlScene(
ValueUtil.CxrSceneType.AI_SCENE, true, actionParams
)
CxrApi.getInstance().setAiEventListener(object : AiEventListener {
override fun onAiEvent(eventType: ValueUtil.CxrAiEventType?, data: String?) {
when (eventType) {
ValueUtil.CxrAiEventType.ACTION_RECOGNITION -> {
val recognitionResult = Gson().fromJson(data, ActionRecognitionResult::class.java)
if (recognitionResult.accuracy > 0.8) {
showPositiveFeedback(recognitionResult.exerciseName, "动作标准!")
} else {
showCorrectionFeedback(recognitionResult.exerciseName, recognitionResult.correctionMessage)
}
}
}
}
})
}
private fun showCorrectionFeedback(exerciseName: String, message: String) {
CxrApi.getInstance().controlScene(
ValueUtil.CxrSceneType.WORD_TIPS, true, null
)
val text = "动作纠正:$message"
CxrApi.getInstance().sendStream(
ValueUtil.CxrStreamType.WORD_TIPS, text.toByteArray(), "correction_text",
object : SendStatusCallback {
override fun onSendSucceed() { Log.d("FitnessApp", "Correction message sent") }
override fun onSendFailed(errorCode: ValueUtil.CxrSendErrorCode?) {
Log.e("FitnessApp", "Failed to send correction message: $errorCode")
}
}
)
}
AR 教练界面与数据可视化
使用自定义页面构建 AR 交互界面。JSON 布局定义了视图结构,支持实时更新数据。
private fun setupARCoachInterface() {
val arCoachJson = """
{
"type": "LinearLayout",
"props": {
"layout_width": "match_parent",
"layout_height": "match_parent",
"orientation": "vertical",
"gravity": "center_horizontal",
"paddingTop": "140dp",
"paddingBottom": "100dp",
"backgroundColor": "#00000000"
},
"children": [
{
"type": "TextView",
"props": {
"id": "tv_instruction",
"text": "请保持背部挺直",
"textSize": "18sp",
"textColor": "#FF00FF00",
"textStyle": "bold"
}
},
{
"type": "TextView",
"props": {
"id": "tv_count",
"text": "0/10",
"textSize": "24sp",
"textColor": "#FFFFFFFF",
"textStyle": "bold"
}
}
]
}
""".trimIndent()
CxrApi.getInstance().openCustomView(arCoachJson)
CxrApi.getInstance().setCustomViewListener(object : CustomViewListener {
override fun onCustomViewOpened() { Log.d("FitnessApp", "Custom view opened") }
override fun onCustomViewClosed() { Log.d("FitnessApp", "Custom view closed") }
})
}
数据可视化模块同样基于自定义页面,通过异步更新避免阻塞主线程,实时展示心率、卡路里等信息。
社交健身挑战
支持好友挑战功能,将挑战数据发送至眼镜端并同步给好友。
class ChallengeActivity : AppCompatActivity() {
private val challenges = mutableListOf<Challenge>(
Challenge("7 天深蹲挑战", "完成 7 天深蹲训练,每天 100 次", 7, 100),
Challenge("30 天心率挑战", "保持心率在 120-150 之间", 30, 0)
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_challenge)
findViewById<Button>(R.id.btn_add_friend_challenge).setOnClickListener {
showAddFriendChallengeDialog()
}
}
private fun createFriendChallenge(friendId: String) {
val challenge = Challenge("与$friendId 的挑战", "一起完成 30 天健身挑战", 30, 0)
saveChallengeToGlasses(challenge)
sendChallengeToFriend(friendId, challenge)
}
private fun saveChallengeToGlasses(challenge: Challenge) {
val challengeJson = Gson().toJson(challenge)
CxrApi.getInstance().sendStream(
ValueUtil.CxrStreamType.CHALLENGE, challengeJson.toByteArray(), "challenge_${challenge.id}",
object : SendStatusCallback {
override fun onSendSucceed() { Log.d("FitnessApp", "Challenge saved") }
override fun onSendFailed(errorCode: ValueUtil.CxrSendErrorCode?) {
Log.e("FitnessApp", "Failed to save challenge: $errorCode")
}
}
)
}
}
挑战与解决方案
动作识别精度:环境光线和用户差异可能影响准确率。我们采用多模态数据融合,结合摄像头和传感器数据,并实现动态阈值调整机制。
private fun adjustRecognitionThreshold(userProfile: UserProfile): Float {
return when {
userProfile.age < 25 -> 0.85f
userProfile.age < 40 -> 0.80f
else -> 0.75f
}
}
AR 界面流畅度:帧率不稳定时,优化 JSON 布局减少元素,并使用 setCustomViewRenderMode 调整渲染模式为 FAST。
电池消耗:长时间运行易耗电。通过智能功耗管理,设置自动休眠和低功耗模式(降低亮度、音量),延长续航。
未来展望
'形随心动'验证了 Rokid CXR-M SDK 在 AR 健身场景的潜力。后续将集成更先进的 AI 模型,拓展内容生态,并与更多智能硬件联动,打造完整的 AR 健身体验。
通过深度整合 SDK 的 AI 场景、自定义页面和提词器功能,我们实现了真正'抬头即见指导'的健身体验,解决了居家健身的核心痛点。随着 SDK 的持续完善,AR 技术将在更多生活场景中发挥重要作用。
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online