diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f106cca..93e831d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -20,6 +20,15 @@
+
+
+
@@ -31,6 +40,8 @@
+
+
diff --git a/app/src/main/java/com/example/lzwcai_terminal_temi/MainActivity.kt b/app/src/main/java/com/example/lzwcai_terminal_temi/MainActivity.kt
index 323d9a1..3b73f03 100644
--- a/app/src/main/java/com/example/lzwcai_terminal_temi/MainActivity.kt
+++ b/app/src/main/java/com/example/lzwcai_terminal_temi/MainActivity.kt
@@ -18,6 +18,7 @@ import com.robotemi.sdk.listeners.OnRobotReadyListener
import com.robotemi.sdk.listeners.OnDetectionStateChangedListener.Companion.DETECTED
import com.robotemi.sdk.listeners.OnDetectionStateChangedListener.Companion.IDLE
import com.robotemi.sdk.navigation.listener.OnReposeStatusChangedListener
+import com.robotemi.sdk.permission.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@@ -25,7 +26,8 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.cancel
class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnGoToLocationStatusChangedListener,
- OnDetectionStateChangedListener, OnReposeStatusChangedListener, SharedPreferences.OnSharedPreferenceChangeListener {
+ OnDetectionStateChangedListener, OnReposeStatusChangedListener, SharedPreferences.OnSharedPreferenceChangeListener,
+ OnRequestPermissionResultListener {
private lateinit var robot: Robot
private lateinit var binding: ActivityMainBinding
@@ -33,13 +35,14 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
private val mainScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
private lateinit var prefs: SharedPreferences
private lateinit var navCon: NavController
+ private lateinit var permissionManager: PermissionManager
+
private var lastArrivalLocation: String? = null
private var lastArrivalAt: Long = 0L
private val fixedFaceScale = 1.0f
private val baseFaceSizeDp = 1000f
+ private var currentTask: String = ""
- // Reception mode
- private var isReceptionMode = false
private var receptionLocation: String = ""
private var receptionText: String = ""
private var receptionDestination: String = ""
@@ -54,6 +57,7 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
robot = Robot.getInstance()
navCon = NavController(robot)
+ permissionManager = PermissionManager(robot)
prefs = getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
@@ -82,6 +86,7 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
robot.addOnGoToLocationStatusChangedListener(this)
robot.addOnDetectionStateChangedListener(this)
robot.addOnReposeStatusChangedListener(this)
+ robot.addOnRequestPermissionResultListener(this)
prefs.registerOnSharedPreferenceChangeListener(this)
mqttManager?.connect()
}
@@ -93,6 +98,7 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
robot.removeOnGoToLocationStatusChangedListener(this)
robot.removeOnDetectionStateChangedListener(this)
robot.removeOnReposeStatusChangedListener(this)
+ robot.removeOnRequestPermissionResultListener(this)
prefs.unregisterOnSharedPreferenceChangeListener(this)
mqttManager?.disconnect()
}
@@ -108,6 +114,21 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
override fun onRobotReady(isReady: Boolean) {
if (isReady) {
Log.i("MainActivity", "Robot is ready!")
+ permissionManager.checkAndRequestPermissions()
+ }
+ }
+
+ override fun onRequestPermissionResult(
+ permission: Permission,
+ grantResult: Int,
+ requestCode: Int
+ ) {
+ if (requestCode == PermissionManager.REQUEST_CODE_TEMI_PERMISSIONS) {
+ if (grantResult == Permission.GRANTED) {
+ Log.i("MainActivity", "Temi permission GRANTED: $permission")
+ } else {
+ Log.w("MainActivity", "Temi permission DENIED: $permission")
+ }
}
}
@@ -115,7 +136,7 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
mqttManager?.handleTtsStatusChange(ttsRequest)
when (ttsRequest.status) {
TtsRequest.Status.STARTED -> {
- Log.i("MainActivity", "TTS started: ${ttsRequest.speech}")
+ Log.i("MainActivity", "TTS started")
binding.animatedEmojiView.currentExpression = AnimatedEmojiView.Expression.TALKING
}
TtsRequest.Status.COMPLETED -> {
@@ -152,8 +173,7 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
}
override fun onDetectionStateChanged(state: Int) {
- // Reception mode logic
- if (isReceptionMode && lastArrivalLocation == receptionLocation) {
+ if (currentTask == "reception" && lastArrivalLocation == receptionLocation) {
when (state) {
DETECTED -> {
if (binding.btnReception.visibility != android.view.View.VISIBLE) {
@@ -171,34 +191,34 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
}
// Home Base logic
- if (lastArrivalLocation?.lowercase() == "home base") {
- when (state) {
- DETECTED -> {
- mainScope.launch {
- HttpManager.workflow_execute(
- context = this@MainActivity,
- apiKey = "wf_865e80f5fc1a4a319474a21d47470863",
- workflowId = "2031297462423851009",
- inputs = emptyMap()
- )
- }
- }
- IDLE -> {
- mainScope.launch {
- HttpManager.workflow_execute(
- context = this@MainActivity,
- apiKey = "wf_c02aa853371345dbb29572641d083c24",
- workflowId = "2031634633458520065",
- inputs = emptyMap()
- )
- }
- }
- }
- }
+ // if (lastArrivalLocation?.lowercase() == "home base") {
+ // when (state) {
+ // DETECTED -> {
+ // mainScope.launch {
+ // HttpManager.workflow_execute(
+ // context = this@MainActivity,
+ // apiKey = "wf_865e80f5fc1a4a319474a21d47470863",
+ // workflowId = "2031297462423851009",
+ // inputs = emptyMap()
+ // )
+ // }
+ // }
+ // IDLE -> {
+ // mainScope.launch {
+ // HttpManager.workflow_execute(
+ // context = this@MainActivity,
+ // apiKey = "wf_c02aa853371345dbb29572641d083c24",
+ // workflowId = "2031634633458520065",
+ // inputs = emptyMap()
+ // )
+ // }
+ // }
+ // }
+ // }
}
fun startReceptionMode(location: String, text: String, destination: String) {
- isReceptionMode = true
+ currentTask = "reception"
receptionLocation = location
receptionText = text
receptionDestination = destination
@@ -209,7 +229,7 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
}
private fun stopReceptionMode() {
- isReceptionMode = false
+ currentTask = ""
receptionLocation = ""
receptionText = ""
receptionDestination = ""
@@ -217,6 +237,11 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
Log.i("MainActivity", "Reception mode stopped")
}
+ fun setCurrentTask(task: String) {
+ currentTask = task
+ Log.i("MainActivity", "Current task set to: $task")
+ }
+
override fun onReposeStatusChanged(status: Int, description: String) {
when (status) {
OnReposeStatusChangedListener.REPOSING_COMPLETE -> {
@@ -266,4 +291,5 @@ class MainActivity : AppCompatActivity(), OnRobotReadyListener, TtsListener, OnG
binding.animatedEmojiView.layoutParams = params
binding.animatedEmojiView.requestLayout()
}
+
}
diff --git a/app/src/main/java/com/example/lzwcai_terminal_temi/MqttManager.kt b/app/src/main/java/com/example/lzwcai_terminal_temi/MqttManager.kt
index 5de334d..c793f99 100644
--- a/app/src/main/java/com/example/lzwcai_terminal_temi/MqttManager.kt
+++ b/app/src/main/java/com/example/lzwcai_terminal_temi/MqttManager.kt
@@ -161,6 +161,10 @@ class MqttManager(
private fun handleJsonCommand(obj: JSONObject) {
val action = obj.optString("action", obj.optString("cmd", obj.optString("type", ""))).lowercase()
when (action) {
+ "charge" -> {
+ speak("前往充电桩", "zh")
+ navController.charge()
+ }
"goto" -> {
val location = obj.optString("location", obj.optString("target", ""))
goTo(location)
@@ -184,7 +188,25 @@ class MqttManager(
stopTts()
}
"patrol" -> {
- navController.randomPatrol()
+ (context as? MainActivity)?.setCurrentTask("patrol")
+ speak("接到巡逻任务", "zh")
+ val flag = obj.optBoolean("flag", true)
+ if (flag) {
+ Log.d(TAG, "navController.randomPatrol() called.")
+ navController.randomPatrol()
+ } else {
+ val locationsArray = obj.optJSONArray("locations")
+ if (locationsArray != null && locationsArray.length() > 0) {
+ val locations = List(locationsArray.length()) {
+ locationsArray.getString(it)
+ }
+ Log.d(TAG, "navController.NavPatrol() called with locations: $locations")
+ navController.NavPatrol(locations)
+ } else {
+ Log.w(TAG, "Patrol command received without locations, falling back to random patrol.")
+ navController.randomPatrol()
+ }
+ }
}
"reception" -> {
val location = obj.optString("location", "前台")
@@ -230,9 +252,7 @@ class MqttManager(
}
private fun stopTts() {
- // Clear buffer
speechBuffer.setLength(0)
-
scope.launch(Dispatchers.Main) {
ttsQueue.clear()
isTtsBusy = false
@@ -254,7 +274,6 @@ class MqttManager(
private fun speak(text: String, langCode: String?) {
val content = text.trim()
if (content.isEmpty()) {
- // Log.w(TAG, "Speak ignored: empty text") // Too noisy for stream?
return
}
val language = resolveLanguage(langCode)
diff --git a/app/src/main/java/com/example/lzwcai_terminal_temi/NavController.kt b/app/src/main/java/com/example/lzwcai_terminal_temi/NavController.kt
index 0436020..0515873 100644
--- a/app/src/main/java/com/example/lzwcai_terminal_temi/NavController.kt
+++ b/app/src/main/java/com/example/lzwcai_terminal_temi/NavController.kt
@@ -5,6 +5,13 @@ import com.robotemi.sdk.Robot
class NavController(private val robot: Robot) {
private val TAG = "NavController"
+ private var playmode = false
+
+ fun charge(): Boolean {
+ playmode = !playmode
+ robot.goTo("home base", playmode)
+ return true
+ }
fun goTo(location: String, backwards: Boolean = false): Boolean {
robot.goTo(location, backwards)
@@ -20,8 +27,12 @@ class NavController(private val robot: Robot) {
return robot.locations
}
- fun patrol(locations: List, nonStop: Boolean = false, times: Int = 1, waiting: Int = 3) {
- robot.patrol(locations, nonStop, times, waiting)
+ fun NavPatrol(locations: List, nonStop: Boolean = false, times: Int = 1, waiting: Int = 3) {
+ try {
+ robot.patrol(locations, nonStop, times, waiting)
+ } catch (e: Exception) {
+ Log.e(TAG, "patrol() command failed.", e)
+ }
}
fun repose(): Boolean {
@@ -31,12 +42,14 @@ class NavController(private val robot: Robot) {
fun randomPatrol() {
val allLocations = getAllLocations()
- if (allLocations.size < 3) {
+ val availablePatrolLocations = allLocations.filter { !it.equals("home base", ignoreCase = true) }
+ if (availablePatrolLocations.size < 3) {
+ Log.w(TAG, "Patrol command ignored: Not enough valid locations (excluding home base). Need at least 3, but found ${availablePatrolLocations.size}.")
return
}
- val patrolCount = (3..minOf(6, allLocations.size)).random()
- val patrolLocations = allLocations.shuffled().take(patrolCount)
-
- patrol(patrolLocations, false, 1, 3)
+ val patrolCount = (3..minOf(6, availablePatrolLocations.size)).random()
+ val patrolLocations = availablePatrolLocations.shuffled().take(patrolCount)
+ Log.i(TAG, "Starting random patrol with $patrolCount locations: ${patrolLocations.joinToString()}.")
+ NavPatrol(patrolLocations, false, 1, 5)
}
}
diff --git a/app/src/main/java/com/example/lzwcai_terminal_temi/PermissionManager.kt b/app/src/main/java/com/example/lzwcai_terminal_temi/PermissionManager.kt
new file mode 100644
index 0000000..2672bdb
--- /dev/null
+++ b/app/src/main/java/com/example/lzwcai_terminal_temi/PermissionManager.kt
@@ -0,0 +1,35 @@
+package com.example.lzwcai_terminal_temi
+
+import android.util.Log
+import com.robotemi.sdk.Robot
+import com.robotemi.sdk.permission.Permission
+
+class PermissionManager(private val robot: Robot) {
+
+ private val TAG = "PermissionManager"
+
+ companion object {
+ const val REQUEST_CODE_TEMI_PERMISSIONS = 101
+ }
+
+ private val requiredPermissions = listOf(
+ Permission.MAP,
+ Permission.SEQUENCE,
+ Permission.FACE_RECOGNITION,
+ Permission.SETTINGS
+ )
+
+ fun checkAndRequestPermissions() {
+
+ val neededPermissions = requiredPermissions.filter {
+ robot.checkSelfPermission(it) != Permission.GRANTED
+ }
+
+ if (neededPermissions.isNotEmpty()) {
+ Log.i(TAG, "Requesting Temi permissions: $neededPermissions")
+ robot.requestPermissions(neededPermissions, REQUEST_CODE_TEMI_PERMISSIONS)
+ } else {
+ Log.i(TAG, "All required Temi permissions are already granted.")
+ }
+ }
+}
diff --git a/test.py b/test.py
new file mode 100644
index 0000000..24cffd1
--- /dev/null
+++ b/test.py
@@ -0,0 +1,100 @@
+import paho.mqtt.client as mqtt
+import json
+import time
+import sys
+import random
+
+# --- MQTT 配置 ---
+# 重要:请将这里替换为您的 MQTT 代理的 IP 地址
+BROKER_IP = "192.168.2.236"
+BROKER_PORT = 1883
+MQTT_TOPIC = "robot/cmd"
+MQTT_USERNAME = "lzwc"
+MQTT_PASSWORD = "Lzwc@4187."
+
+# --- 要进行流式传输的文本 ---
+# 您可以更改此文本
+TEXT_TO_STREAM = "你好,我是一个先进的人工智能助理。我的设计目标是理解并生成自然语言,从而能够与人类进行流畅的对话。我可以回答问题、提供信息、撰写文章,甚至进行一些基础的编程任务。这个流式传输演示旨在展示我如何将长篇回复分解成小的数据块,并实时发送给客户端,从而创造出一种更具互动性和即时性的体验。希望这次演示能够清晰地展示我的能力。"
+
+# --- 流媒体参数 ---
+# 每个数据块中发送的字符长度范围
+MIN_CHUNK_SIZE = 2
+MAX_CHUNK_SIZE = 8
+# 块之间的延迟(秒)
+STREAM_DELAY = 0.1
+
+def on_connect(client, userdata, flags, rc):
+ """客户端连接到代理时的回调。"""
+ if rc == 0:
+ print("成功连接到 MQTT 代理!")
+ else:
+ print(f"连接失败, 返回码 {rc}\n")
+ sys.exit(1)
+
+def on_publish(client, userdata, mid):
+ """消息发布时的回调。"""
+ # 默认注释掉,因为可能会产生大量输出
+ # print(f"已发布消息,mid: {mid}")
+ pass
+
+def create_mqtt_client():
+ """创建并配置 MQTT 客户端。"""
+ client = mqtt.Client()
+ client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
+ client.on_connect = on_connect
+ client.on_publish = on_publish
+ return client
+
+def stream_text(client, text_to_stream):
+ """将给定的文本以数据块的形式流式传输到 MQTT 主题。"""
+ print(f"开始向主题 '{MQTT_TOPIC}' 流式传输文本:")
+ print(f"文本: {text_to_stream}")
+
+ index = 0
+ while index < len(text_to_stream):
+ # 生成一个随机的块大小
+ chunk_size = random.randint(MIN_CHUNK_SIZE, MAX_CHUNK_SIZE)
+ # 获取块,确保不会超出文本长度
+ chunk = text_to_stream[index:index + chunk_size]
+ index += len(chunk)
+
+ # 创建 JSON 负载
+ payload = {
+ "action": "stream",
+ "text": chunk,
+ "lang": "zh" # 假设是中文,如果需要可以更改
+ }
+ payload_json = json.dumps(payload, ensure_ascii=False)
+
+ # 发布消息
+ result = client.publish(MQTT_TOPIC, payload_json)
+
+ # 检查发布是否成功
+ if result.rc != mqtt.MQTT_ERR_SUCCESS:
+ print(f"发送消息失败: {mqtt.error_string(result.rc)}")
+ else:
+ print(f"已发送块: '{chunk}'")
+
+ # 等待一小段时间以模拟流式传输
+ time.sleep(STREAM_DELAY)
+
+ print("\n流式传输完成。")
+
+def main():
+ """运行 MQTT 流式脚本的主函数。"""
+ client = create_mqtt_client()
+
+ try:
+ client.connect(BROKER_IP, BROKER_PORT)
+ except Exception as e:
+ print(f"连接到代理 {BROKER_IP}:{BROKER_PORT} 时出错。请检查 IP 地址。")
+ print(f"错误: {e}")
+ sys.exit(1)
+
+ stream_text(client, TEXT_TO_STREAM)
+
+ client.disconnect()
+ print("已从 MQTT 代理断开。")
+
+if __name__ == "__main__":
+ main()