首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Rokid CXR-M SDK 实战:打造覆盖食材管理、AR 指引、云端同步的智能烹饪助手

Rokid CXR-M SDK 实战:打造覆盖食材管理、AR 指引、云端同步的智能烹饪助手

原创
作者头像
用户11934283
发布2025-11-29 20:05:48
发布2025-11-29 20:05:48
2110
举报

​编辑本文围绕烹饪场景的全流程需求,详细阐述如何利用 Rokid CXR-M SDK 的核心与扩展能力,开发一款功能完整、体验流畅的智能厨艺助手应用。通过手机与 Rokid Glasses 的深度协同,结合 JSON 配置化设计与多模块联动,实现 AR 菜谱可视化、食材量化指引、多模式交互、烹饪数据记录、云端菜谱同步等全场景功能,既保证功能完整性,又避免冗余 SDK 调用,为开发者提供一套 “实用全面、易落地、可扩展” 的 AI+AR 烹饪解决方案,让不同水平的用户都能轻松做出美味菜品。

一、项目背景与核心价值

1.1 烹饪场景的全流程痛点

居家烹饪不仅需要实时指引,还涉及食材管理、菜谱扩展、数据追溯等全流程需求:新手面临 “步骤看不懂、用量拿不准、操作断档” 的问题;进阶用户需要 “自定义菜谱、云端同步、烹饪记录” 功能;家庭用户关注 “食材过期提醒、多人共享菜谱” 等实用功能。传统工具仅解决单一环节痛点,而 Rokid CXR-M SDK 的多能力协同,能实现 “从食材准备到烹饪完成” 的全流程赋能。

1.2 Rokid 设备与 SDK 的全功能赋能

Rokid Glasses 的 AR 显示 + 语音交互 + 图像采集能力,配合 CXR-M SDK 的核心(蓝牙连接、AR 渲染、TTS)与扩展(Wi-Fi P2P、相机控制、场景回调)API,构建 “虚实融合 + 全流程覆盖” 的闭环系统:AR 界面提供精准指引,蓝牙 + Wi-Fi 双模通信保障数据传输,相机控制支持食材识别,TTS + 按键 + 语音指令实现多模式交互,既满足核心烹饪指引需求,又覆盖食材管理、数据记录等延伸场景。

二、项目整体设计

2.1 核心功能模块

围绕烹饪全流程,设计五大实用模块,兼顾基础需求与进阶功能:

  1. JSON 配置化 AR 菜谱模块:通过 JSON 统一管理界面与菜谱数据,支持文本、图标、步骤进度多维度展示;
  2. 多模式交互模块:支持眼镜按键、语音指令、手机触控三种交互方式,适配不同烹饪场景;
  3. 食材管理模块:支持食材库存录入、过期提醒、基于食材推荐菜谱,减少浪费;
  4. 烹饪数据记录模块:记录烹饪时长、完成状态、用户评价,形成个性化烹饪档案;
  5. 云端菜谱同步模块:支持本地 JSON 菜谱与云端同步,丰富菜品选择,支持用户分享。

2.2 技术架构设计

采用 “端 - 边 - 云” 轻量协同架构,分层明确且无冗余,兼顾功能完整性与性能:

  • 硬件层:Rokid Glasses(AR 显示、交互、语音输出、图像采集)、智能手机(数据处理、存储、网络通信);
  • 通信层:基于 CXR-M SDK 的蓝牙 + Wi-Fi P2P 双模通信(蓝牙负责控制指令,Wi-Fi P2P 负责高清资源 / 图像传输);
  • 业务层:JSON 解析引擎、AR 界面渲染模块、交互响应中心、食材管理模块、数据记录与同步模块;
  • 数据层:本地 SQLite 数据库(轻量化存储)+ 云端 JSON 菜谱库(支持同步与分享)。

三、核心技术实现(全功能 + JSON 配置)

3.1 设备连接与双模通信

结合蓝牙与 Wi-Fi P2P 双模通信,满足不同数据传输需求,确保功能完整性:

代码语言:javascript
复制
class CookingDeviceManager {companion object {private lateinit var context: Context
        private var isBluetoothConnected = falseprivate var isWifiP2PConnected = falsefun init(context: Context) {this.context = context
            CxrApi.getInstance().init(context) // SDK核心初始化}// 蓝牙连接(控制指令、文本传输)fun connectBluetooth(bluetoothDevice: BluetoothDevice) {
            CxrApi.getInstance().initBluetooth(context, bluetoothDevice, object : BluetoothStatusCallback {override fun onConnected() {
                    isBluetoothConnected = truesendVoiceTip("蓝牙连接成功,正在初始化Wi-Fi传输")initWifiP2P() // 自动初始化Wi-Fi P2P}override fun onDisconnected() {
                    isBluetoothConnected = falsesendVoiceTip("蓝牙连接断开,请重新配对")}override fun onFailed(errorCode: ValueUtil.CxrBluetoothErrorCode?) {sendToast("蓝牙连接失败,错误码:${errorCode?.name}")}override fun onConnectionInfo(socketUuid: String?, macAddress: String?, rokidAccount: String?, glassesType: Int) {
                    Log.d("DeviceManager", "设备信息:MAC=$macAddress, 型号=$glassesType")}})}// Wi-Fi P2P初始化(高清资源、图像传输)private fun initWifiP2P() {
            CxrApi.getInstance().initWifiP2P(object : WifiP2PStatusCallback {override fun onConnected() {
                    isWifiP2PConnected = truesendVoiceTip("Wi-Fi连接成功,可加载高清菜谱资源")}override fun onDisconnected() {
                    isWifiP2PConnected = falsesendVoiceTip("Wi-Fi连接断开,切换至基础模式")}override fun onFailed(errorCode: ValueUtil.CxrWifiErrorCode?) {sendToast("Wi-Fi连接失败,仅支持基础功能")}})}// 语音播报(SDK核心TTS API)fun sendVoiceTip(content: String) {if (isBluetoothConnected) {
                CxrApi.getInstance().sendTtsContent(content)}}// 发送JSON数据(如菜谱配置)fun sendJsonData(jsonStr: String, callback: SendStatusCallback? = null) {if (isBluetoothConnected) {
                CxrApi.getInstance().sendStream(
                    ValueUtil.CxrStreamType.DATA,
                    jsonStr.toByteArray(),"recipe_data.json",
                    callback
                )}}// 检查设备连接状态fun isDeviceReady() = isBluetoothConnected
        fun isHighSpeedMode() = isWifiP2PConnected
    }}

3.2 JSON 配置化 AR 菜谱模块

通过 JSON 实现 AR 界面结构、菜谱数据、资源配置的统一管理,支持文本、图标、进度条等多元素展示,兼顾美观与实用:

代码语言:javascript
复制
class ARRecipeGuide {companion object {private var currentStep = 0private lateinit var recipeData: RecipeJson
        private val AR_BASE_CONFIG = """
        {
          "type": "LinearLayout",
          "props": {
            "layout_width": "match_parent",
            "layout_height": "match_parent",
            "orientation": "vertical",
            "gravity": "top|center",
            "backgroundColor": "#80000000",
            "padding": "30dp"
          },
          "children": [
            {
              "type": "TextView",
              "props": {
                "id": "tv_title",
                "textSize": "24sp",
                "textColor": "#FFFFFF",
                "marginBottom": "15dp",
                "textStyle": "bold"
              }
            },
            {
              "type": "ProgressBar",
              "props": {
                "id": "pb_step",
                "layout_width": "250dp",
                "layout_height": "8dp",
                "progress": 0,
                "max": 100,
                "progressColor": "#FFCC00",
                "bgColor": "#AAAAAA",
                "marginBottom": "15dp"
              }
            },
            {
              "type": "TextView",
              "props": {
                "id": "tv_progress",
                "textSize": "16sp",
                "textColor": "#FFCC00",
                "marginBottom": "20dp"
              }
            },
            {
              "type": "ImageView",
              "props": {
                "id": "iv_step_icon",
                "layout_width": "120dp",
                "layout_height": "120dp",
                "marginBottom": "15dp"
              }
            },
            {
              "type": "TextView",
              "props": {
                "id": "tv_step_desc",
                "textSize": "18sp",
                "textColor": "#FFFFFF",
                "maxWidth": "320dp",
                "gravity": "center",
                "marginBottom": "10dp"
              }
            },
            {
              "type": "TextView",
              "props": {
                "id": "tv_step_ingredient",
                "textSize": "16sp",
                "textColor": "#AAAAAA",
                "marginBottom": "10dp"
              }
            },
            {
              "type": "TextView",
              "props": {
                "id": "tv_step_time",
                "textSize": "16sp",
                "textColor": "#4CAF50"
              }
            }
          ]
        }
        """.trimIndent()// 初始化AR菜谱(加载JSON配置+资源)fun initARGuide(recipeJson: RecipeJson) {this.recipeData = recipeJson
            currentStep = 0val totalSteps = recipeData.steps.size
            val progress = ((currentStep + 1).toFloat() / totalSteps * 100).toInt()// 合并基础配置与菜谱数据val arViewJson = mergeARConfig(AR_BASE_CONFIG, recipeJson, currentStep, progress)val status = CxrApi.getInstance().openCustomView(arViewJson)if (status == ValueUtil.CxrStatus.REQUEST_SUCCEED) {val stepData = recipeJson.steps[currentStep]// 上传步骤图标(Wi-Fi连接时加载高清图,否则用低清图)if (CookingDeviceManager.isHighSpeedMode()) {uploadStepIcon(stepData.hdIconName)} else {uploadStepIcon(stepData.lqIconName)}
                CookingDeviceManager.sendVoiceTip("第一步,${stepData.desc},预计${stepData.time}分钟")} else {
                CookingDeviceManager.sendVoiceTip("菜谱加载失败,请重试")}}// 合并AR配置与菜谱数据private fun mergeARConfig(baseConfig: String, recipe: RecipeJson, stepIndex: Int, progress: Int): String {val baseJson = JsonParser.parseString(baseConfig).asJsonObject
            val stepData = recipe.steps[stepIndex]val totalSteps = recipe.steps.size

            baseJson.getAsJsonArray("children").forEach { child ->val childObj = child.asJsonObject
                val childProps = childObj.getAsJsonObject("props")when (childProps.get("id")?.asString) {"tv_title" -> childProps.addProperty("text", recipe.name)"pb_step" -> childProps.addProperty("progress", progress)"tv_progress" -> childProps.addProperty("text", "步骤 ${stepIndex+1}/$totalSteps")"tv_step_desc" -> childProps.addProperty("text", stepData.desc)"tv_step_ingredient" -> childProps.addProperty("text", "食材:${stepData.ingredient}")"tv_step_time" -> childProps.addProperty("text", "预计时长:${stepData.time}分钟")"iv_step_icon" -> childProps.addProperty("name", if (CookingDeviceManager.isHighSpeedMode()) stepData.hdIconName else stepData.lqIconName)}}return Gson().toJson(baseJson)}// 上传步骤图标(SDK扩展API)private fun uploadStepIcon(iconName: String) {val iconList = mutableListOf<IconInfo>()val bitmap = BitmapFactory.decodeResource(context.resources, context.resources.getIdentifier(iconName, "drawable", context.packageName))val base64Str = bitmapToBase64(bitmap)
            iconList.add(IconInfo(iconName, base64Str))
            CxrApi.getInstance().sendCustomViewIcons(iconList)}// Bitmap转Base64private fun bitmapToBase64(bitmap: Bitmap): String {val bos = ByteArrayOutputStream()
            bitmap.compress(Bitmap.CompressFormat.PNG, 80, bos)val bytes = bos.toByteArray()return Base64.encodeToString(bytes, Base64.DEFAULT)}// 切换下一步fun nextStep() {if (currentStep >= recipeData.steps.size - 1) {finishCooking()return}
            currentStep++val totalSteps = recipeData.steps.size
            val progress = ((currentStep + 1).toFloat() / totalSteps * 100).toInt()val stepData = recipeData.steps[currentStep]// 构建更新JSONval updateJson = """
            [
              {
                "action": "update",
                "id": "pb_step",
                "props": {"progress": $progress}
              },
              {
                "action": "update",
                "id": "tv_progress",
                "props": {"text": "步骤 ${currentStep+1}/$totalSteps"}
              },
              {
                "action": "update",
                "id": "tv_step_desc",
                "props": {"text": "${stepData.desc}"}
              },
              {
                "action": "update",
                "id": "tv_step_ingredient",
                "props": {"text": "食材:${stepData.ingredient}"}
              },
              {
                "action": "update",
                "id": "tv_step_time",
                "props": {"text": "预计时长:${stepData.time}分钟"}
              },
              {
                "action": "update",
                "id": "iv_step_icon",
                "props": {"name": "${if (CookingDeviceManager.isHighSpeedMode()) stepData.hdIconName else stepData.lqIconName}"}
              }
            ]
            """.trimIndent()

            CxrApi.getInstance().updateCustomView(updateJson)// 上传新步骤图标if (CookingDeviceManager.isHighSpeedMode()) {uploadStepIcon(stepData.hdIconName)} else {uploadStepIcon(stepData.lqIconName)}
            CookingDeviceManager.sendVoiceTip("下一步,${stepData.desc},预计${stepData.time}分钟")}// 烹饪完成private fun finishCooking() {val updateJson = """
            [
              {
                "action": "update",
                "id": "pb_step",
                "props": {"progress": 100}
              },
              {
                "action": "update",
                "id": "tv_progress",
                "props": {"text": "烹饪完成!"}
              },
              {
                "action": "update",
                "id": "tv_step_desc",
                "props": {"text": "恭喜完成${recipeData.name},快去品尝吧~"}
              },
              {
                "action": "update",
                "id": "tv_step_ingredient",
                "props": {"text": "感谢使用AR智慧烹饪助手"}
              },
              {
                "action": "update",
                "id": "tv_step_time",
                "props": {"text": ""}
              },
              {
                "action": "update",
                "id": "iv_step_icon",
                "props": {"name": "cooking_finish"}
              }
            ]
            """.trimIndent()
            CxrApi.getInstance().updateCustomView(updateJson)uploadStepIcon("cooking_finish")
            CookingDeviceManager.sendVoiceTip("烹饪完成,恭喜你")// 记录烹饪数据
            CookingRecordManager.saveCookingRecord(recipeData.id, recipeData.name)}// 关闭AR界面fun closeARGuide() {
            CxrApi.getInstance().closeCustomView()}}}// 全功能菜谱JSON数据类data class RecipeJson(val id: Int,val name: String,val difficulty: String, // 难度:简单/中等/困难val totalTime: Int, // 总时长(分钟)val steps: List<RecipeStepJson>)data class RecipeStepJson(val desc: String, // 步骤描述val ingredient: String, // 食材用量val time: Int, // 预计时长(分钟)val hdIconName: String, // 高清图标名称val lqIconName: String // 低清图标名称(蓝牙模式下使用))

3.3 多模式交互模块

支持眼镜按键、语音指令、手机触控三种交互方式,适配烹饪中 “双手油污”“远距离操作” 等不同场景:

代码语言:javascript
复制
class CookingInteractionManager {companion object {// 初始化眼镜按键监听(SDK核心交互API)fun initKeyListener() {
            CxrApi.getInstance().setAiEventListener(object : AiEventListener {override fun onAiKeyDown() {// 短按:重复当前步骤;长按:下一步Handler(Looper.getMainLooper()).postDelayed({
                        ARRecipeGuide.nextStep()}, 500) // 长按500ms触发下一步}override fun onAiKeyUp() {// 短按松开:重复当前步骤val currentStepData = ARRecipeGuide.recipeData.steps[ARRecipeGuide.currentStep]
                    CookingDeviceManager.sendVoiceTip("当前步骤:${currentStepData.desc},所需食材:${currentStepData.ingredient}")}override fun onAiExit() {// 退出按键:关闭AR界面
                    ARRecipeGuide.closeARGuide()
                    CookingDeviceManager.sendVoiceTip("烹饪已取消")}})}// 语音指令识别(支持多指令)fun handleVoiceCommand(command: String) {when {
                command.contains("下一步") -> ARRecipeGuide.nextStep()
                command.contains("重复") -> {val currentStepData = ARRecipeGuide.recipeData.steps[ARRecipeGuide.currentStep]
                    CookingDeviceManager.sendVoiceTip("当前步骤:${currentStepData.desc},所需食材:${currentStepData.ingredient}")}
                command.contains("暂停") -> {
                    CookingDeviceManager.sendVoiceTip("已暂停,说继续或按眼镜按键恢复")}
                command.contains("继续") -> {
                    CookingDeviceManager.sendVoiceTip("已继续烹饪")}
                command.contains("退出") -> ARRecipeGuide.closeARGuide()
                command.contains("难度") -> {
                    CookingDeviceManager.sendVoiceTip("当前菜品难度:${ARRecipeGuide.recipeData.difficulty}")}
                command.contains("总时长") -> {
                    CookingDeviceManager.sendVoiceTip("当前菜品总时长:${ARRecipeGuide.recipeData.totalTime}分钟")}}}// 手机触控交互(配合APP界面)fun onPhoneTouch(action: String) {when (action) {"next_step" -> ARRecipeGuide.nextStep()"repeat_step" -> handleVoiceCommand("重复")"exit" -> ARRecipeGuide.closeARGuide()}}}}

3.4 食材管理与数据记录模块

采用轻量化 SQLite 数据库存储食材与烹饪记录,支持 JSON 格式导入 / 导出,兼顾本地使用与云端同步:

代码语言:javascript
复制
class IngredientManager {companion object {private lateinit var db: SQLiteDatabase
        private const val DB_NAME = "cooking_db"private const val TABLE_INGREDIENT = "ingredient"// 初始化数据库fun init(context: Context) {
            db = context.openOrCreateDatabase(DB_NAME, Context.MODE_PRIVATE, null)// 创建食材表
            db.execSQL("CREATE TABLE IF NOT EXISTS $TABLE_INGREDIENT (" +"id INTEGER PRIMARY KEY AUTOINCREMENT," +"name TEXT NOT NULL," +"quantity TEXT NOT NULL," +"add_time INTEGER NOT NULL," +"expire_time INTEGER NOT NULL)")}// 添加食材(支持JSON导入)fun addIngredient(ingredientJson: String): Boolean {return try {val ingredient = Gson().fromJson(ingredientJson, Ingredient::class.java)val values = ContentValues().apply {put("name", ingredient.name)put("quantity", ingredient.quantity)put("add_time", ingredient.addTime)put("expire_time", ingredient.expireTime)}
                db.insert(TABLE_INGREDIENT, null, values) != -1L} catch (e: Exception) {false}}// 检查过期食材(每天启动时调用)fun checkExpiredIngredients(): List<String> {val expiredList = mutableListOf<String>()val cursor = db.query(TABLE_INGREDIENT, null, "expire_time < ?", arrayOf(System.currentTimeMillis().toString()), null, null, null)while (cursor.moveToNext()) {val name = cursor.getString(cursor.getColumnIndexOrThrow("name"))
                expiredList.add(name)}
            cursor.close()// 语音提示过期食材if (expiredList.isNotEmpty()) {
                CookingDeviceManager.sendVoiceTip("以下食材已过期:${expiredList.joinToString("、")},请及时处理")}return expiredList
        }// 根据食材推荐菜谱(匹配度≥60%)fun recommendRecipes(recipes: List<RecipeJson>): List<RecipeJson> {val stockIngredients = mutableListOf<String>()val cursor = db.query(TABLE_INGREDIENT, arrayOf("name"), null, null, null, null, null)while (cursor.moveToNext()) {
                stockIngredients.add(cursor.getString(0))}
            cursor.close()return recipes.filter { recipe ->val recipeIngredients = recipe.steps.flatMap { step ->
                    step.ingredient.split("、").map { it.split(":")[0].trim() }}.distinct()val matchCount = recipeIngredients.count { stockIngredients.contains(it) }
                matchCount.toFloat() / recipeIngredients.size >= 0.6}}// 导出食材为JSONfun exportIngredientsToJson(): String {val ingredients = mutableListOf<Ingredient>()val cursor = db.query(TABLE_INGREDIENT, null, null, null, null, null, null)while (cursor.moveToNext()) {
                ingredients.add(Ingredient(
                        id = cursor.getInt(cursor.getColumnIndexOrThrow("id")),
                        name = cursor.getString(cursor.getColumnIndexOrThrow("name")),
                        quantity = cursor.getString(cursor.getColumnIndexOrThrow("quantity")),
                        addTime = cursor.getLong(cursor.getColumnIndexOrThrow("add_time")),
                        expireTime = cursor.getLong(cursor.getColumnIndexOrThrow("expire_time"))))}
            cursor.close()return Gson().toJson(ingredients)}}}// 食材数据类data class Ingredient(val id: Int = 0,val name: String,val quantity: String,val addTime: Long = System.currentTimeMillis(),val expireTime: Long
)// 烹饪记录管理class CookingRecordManager {companion object {private lateinit var db: SQLiteDatabase
        private const val TABLE_RECORD = "cooking_record"fun init(context: Context) {
            db = context.openOrCreateDatabase(DB_NAME, Context.MODE_PRIVATE, null)// 创建烹饪记录表
            db.execSQL("CREATE TABLE IF NOT EXISTS $TABLE_RECORD (" +"id INTEGER PRIMARY KEY AUTOINCREMENT," +"recipe_id INTEGER NOT NULL," +"recipe_name TEXT NOT NULL," +"cooking_time INTEGER NOT NULL," +"finish_time INTEGER NOT NULL," +"rating INTEGER DEFAULT 0)") // 评分:0-5分}// 保存烹饪记录fun saveCookingRecord(recipeId: Int, recipeName: String) {val values = ContentValues().apply {put("recipe_id", recipeId)put("recipe_name", recipeName)put("cooking_time", System.currentTimeMillis() - startTime) // 假设startTime在启动烹饪时记录put("finish_time", System.currentTimeMillis())}
            db.insert(TABLE_RECORD, null, values)}// 导出记录为JSONfun exportRecordsToJson(): String {val records = mutableListOf<CookingRecord>()val cursor = db.query(TABLE_RECORD, null, null, null, null, null, "finish_time DESC")while (cursor.moveToNext()) {
                records.add(CookingRecord(
                        id = cursor.getInt(cursor.getColumnIndexOrThrow("id")),
                        recipeId = cursor.getInt(cursor.getColumnIndexOrThrow("recipe_id")),
                        recipeName = cursor.getString(cursor.getColumnIndexOrThrow("recipe_name")),
                        cookingTime = cursor.getLong(cursor.getColumnIndexOrThrow("cooking_time")),
                        finishTime = cursor.getLong(cursor.getColumnIndexOrThrow("finish_time")),
                        rating = cursor.getInt(cursor.getColumnIndexOrThrow("rating"))))}
            cursor.close()return Gson().toJson(records)}}}// 烹饪记录数据类data class CookingRecord(val id: Int,val recipeId: Int,val recipeName: String,val cookingTime: Long, // 实际烹饪时长(毫秒)val finishTime: Long,val rating: Int // 评分)

3.5 云端菜谱同步模块

支持本地 JSON 菜谱与云端同步,通过 HTTP 接口实现菜谱上传、下载、分享,扩展菜品来源:

代码语言:javascript
复制
class CloudRecipeManager {companion object {private const val CLOUD_API_URL = "https://api.cooking-assistant.com/recipes"// 从云端下载菜谱(JSON格式)suspend fun downloadCloudRecipes(): List<RecipeJson>? {return try {val response = RetrofitClient.instance.getCloudRecipes()if (response.isSuccessful) {
                    response.body()?.let {Gson().fromJson(it, object : TypeToken<List<RecipeJson>>() {}.type)}} else {null}} catch (e: Exception) {null}}// 上传本地菜谱到云端(JSON格式)suspend fun uploadLocalRecipe(recipeJson: RecipeJson): Boolean {return try {val jsonStr = Gson().toJson(recipeJson)val response = RetrofitClient.instance.uploadRecipe(jsonStr)
                response.isSuccessful
            } catch (e: Exception) {false}}// 分享菜谱(生成JSON分享链接)fun shareRecipe(recipeJson: RecipeJson): String {val jsonStr = Gson().toJson(recipeJson)val base64Str = Base64.encodeToString(jsonStr.toByteArray(), Base64.URL_SAFE)return "$CLOUD_API_URL/share?data=$base64Str"}}}// Retrofit客户端(简化版)object RetrofitClient {private val retrofit = Retrofit.Builder().baseUrl(CLOUD_API_URL).addConverterFactory(ScalarsConverterFactory.create()).build()val instance = retrofit.create(RecipeApi::class.java)}// API接口interface RecipeApi {@GET("/list")suspend fun getCloudRecipes(): Response<String>@POST("/upload")@Bodysuspend fun uploadRecipe(@Body jsonStr: String): Response<Unit>}

四、应用使用流程

4.1 准备阶段

  1. 用户安装应用后,完成简单注册,初始化本地数据库;
  2. 录入食材库存(手动输入或 JSON 导入),应用自动检查过期食材并提示;
  3. 打开蓝牙 + Wi-Fi,配对 Rokid Glasses,设备自动建立双模通信;
  4. 应用根据库存食材推荐菜谱,用户可选择本地菜谱或从云端下载新菜谱。

4.2 烹饪阶段

  1. 启动烹饪后,AR 界面通过 JSON 配置加载菜品信息、步骤进度条、图标、操作描述、食材用量和预计时长;
  2. 语音播报当前步骤详情,用户按指引操作;
  3. 完成后,可通过 “长按眼镜按键”“语音说下一步” 或 “手机点击下一步” 切换步骤,AR 界面实时更新;
  4. 烹饪中可通过语音查询 “难度”“总时长”,或说 “重复” 重新收听当前步骤;
  5. 需暂停时说 “暂停”,恢复时说 “继续”,全程无需触碰油污敏感的设备屏幕。

4.3 结束阶段

  1. 所有步骤完成后,AR 界面显示 “烹饪完成” 提示,语音同步播报,应用自动记录烹饪时长;
  2. 用户可对菜品进行评分(1-5 分),评分存入本地数据库;
  3. 支持将烹饪记录、自定义菜谱导出为 JSON,或上传到云端分享给他人;
  4. 下次使用时,可查看历史烹饪记录,或通过导入 JSON 快速恢复食材 / 菜谱数据。

五、技术优化与适配(全场景兼容)

5.1 性能优化

  1. SDK 调用优化:根据场景动态选择 SDK API,蓝牙模式下仅调用核心 API,Wi-Fi 模式下启用扩展 API,平衡功能与功耗;
  2. JSON 优化:菜谱 JSON 采用分层加载,优先加载当前步骤数据,后续步骤异步加载,减少启动延迟;
  3. 资源优化:图标区分高清 / 低清版本,根据网络状态自动切换,Wi-Fi 环境下加载高清图,蓝牙环境下加载低清图,节省带宽。

5.2 场景适配

  1. 光线适配:AR 界面背景透明度和文字对比度通过 JSON 配置支持手动调节,适配厨房强光、弱光等不同环境;
  2. 设备适配:AR 界面元素尺寸使用 dp 单位,依赖 SDK 的自适应布局,兼容 Rokid Glasses 全系列型号;
  3. 网络适配:无网络时仅使用本地 JSON 菜谱和蓝牙通信,核心功能不受影响;有网络时支持云端同步,丰富功能体验;
  4. 用户适配:菜谱难度分 “简单 / 中等 / 困难”,步骤描述兼顾新手和进阶用户,食材用量量化(如 “5ml”“1 小勺”),避免 “少许”“适量” 的模糊表述。

六、总结与展望

本项目基于 Rokid CXR-M SDK 的核心与扩展能力,结合 JSON 配置化设计,打造了一款功能完整、体验流畅的 AR 智慧烹饪助手。核心优势在于 “全流程覆盖 + 灵活配置 + 多模式交互”:通过 JSON 统一管理界面与数据,实现 “零代码扩展菜谱”;支持蓝牙 + Wi-Fi 双模通信,兼顾稳定性与功能丰富度;多模式交互适配烹饪场景的实际需求,真正实现 “解放双手”。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、项目背景与核心价值
    • 1.1 烹饪场景的全流程痛点
    • 1.2 Rokid 设备与 SDK 的全功能赋能
  • 二、项目整体设计
    • 2.1 核心功能模块
    • 2.2 技术架构设计
  • 三、核心技术实现(全功能 + JSON 配置)
    • 3.1 设备连接与双模通信
    • 3.2 JSON 配置化 AR 菜谱模块
    • 3.3 多模式交互模块
    • 3.4 食材管理与数据记录模块
    • 3.5 云端菜谱同步模块
  • 四、应用使用流程
    • 4.1 准备阶段
    • 4.2 烹饪阶段
    • 4.3 结束阶段
  • 五、技术优化与适配(全场景兼容)
    • 5.1 性能优化
    • 5.2 场景适配
  • 六、总结与展望
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档