头域相关功能开发
1. 概述
GR-Head 是 GR3 机器人头部开发模块,运行于头部 RK3588 Android 主控。本文档说明头部基础硬件能力、Android 开发环境、设备连接方式,以及摄像头、麦克风、扬声器和 SPI 眼屏的基础使用方法。
| 元素 | 数值 |
|---|---|
| 主控平台 | RK3588 |
| 操作系统 | Android 12 |
| 默认 IP | 192.168.137.200 |
| 开发方式 | Android 应用开发 |
| 主要硬件 | RGB 摄像头、麦克风、扬声器、SPI 眼屏 |
2. 硬件能力
| 硬件 | 说明 |
|---|---|
| 单目 RGB 摄像头 | 支持图像采集,可用于预览、拍照和图像处理。支持硬件帧同步功能。 |
| 领夹式麦克风 | 支持音频采集。 |
| 扬声器系统 | 支持音频播放。 |
| SPI 眼屏 | 支持眼睛表情控制。 |
3. Android 开发环境
开发前需准备以下工具:
| 工具 | 说明 |
|---|---|
| Android Studio | Android 应用开发、编译和调试工具。 |
| JDK 11 | Android 工程构建环境。 |
adb | 连接设备、安装应用和查看日志。 |
scrcpy | 投屏显示 Android 运行画面。 |
Android Studio 下载地址:
Text
https://developer.android.google.cn/studio?hl=zh-cn
配置完成后,确认终端可执行:
Bash
java -version
adb version
scrcpy --version
4. 设备连接与调试
头部 RK3588 默认 IP 为:
Text
192.168.137.200
开发机需先连接机器人内部网络:
| 方式 | 说明 |
|---|---|
| 有线连接 | 网线一端接机器人背部网口,另一端接开发机网口。 |
| 无线连接 | 开发机连接机器人 Wi-Fi,例如 GR301AA0001_5G。 |
连接网络后执行:
Bash
adb connect 192.168.137.200:5555
adb devices
投屏调试:
Bash
scrcpy --no-audio
安装应用与查看日志:
Bash
adb install -r your_app.apk
adb logcat
5. Android 权限
在 AndroidManifest.xml 中添加所需的权限:
5.1 摄像头权限
XML
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
5.2 麦克风权限
XML
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.hardware.microphone" />
应用安装后,建议在系统设置中确认摄像头和麦克风权限已授权。
6. 摄像头使用方法
头部 RGB 摄像头可通过 Android Camera2 API 或传统 Camera API 调用。以下示例使用 Camera2 API 打开摄像头并显示实时画面。
6.1 创建 Camera Activity
创建 CameraActivity.kt,初始化 TextureView 和 CameraManager:
Kotlin
import android.Manifest
import android.content.pm.PackageManager
import android.graphics.SurfaceTexture
import android.hardware.camera2.*
import android.os.*
import android.util.Log
import android.view.Surface
import android.view.TextureView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
class CameraActivity : AppCompatActivity() {
private lateinit var textureView: TextureView
private lateinit var cameraManager: CameraManager
private var cameraDevice: CameraDevice? = null
private var captureSession: CameraCaptureSession? = null
private var previewRequestBuilder: CaptureRequest.Builder? = null
private var currentCameraId: String? = null
private val mainHandler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
textureView = TextureView(this)
setContentView(textureView)
cameraManager = getSystemService(CAMERA_SERVICE) as CameraManager
textureView.surfaceTextureListener = textureListener
}
6.2 监听 TextureView 状态
当 TextureView 可用时,打开摄像头并注册摄像头可用性监听:
Kotlin
private val textureListener = object : TextureView.SurfaceTextureListener {
override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
Log.i(TAG, "SurfaceTexture available: ${width}x$height")
openCamera()
registerCameraAvailabilityCallback()
}
override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {
Log.i(TAG, "SurfaceTexture size changed: ${width}x$height")
}
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
Log.i(TAG, "SurfaceTexture destroyed")
closeCamera()
return true
}
override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {}
}
6.3 注册摄像头可用性监听
通过 CameraManager.AvailabilityCallback 监听摄像头可用和不可用状态:
Kotlin
private fun registerCameraAvailabilityCallback() {
cameraManager.registerAvailabilityCallback(object : CameraManager.AvailabilityCallback() {
override fun onCameraAvailable(cameraId: String) {
Log.i(TAG, "Camera available: $cameraId")
}
override fun onCameraUnavailable(cameraId: String) {
Log.w(TAG, "Camera unavailable: $cameraId")
}
}, mainHandler)
}
6.4 打开前置摄像头
遍历 系统摄像头列表,查找前置摄像头并打开:
Kotlin
private fun openCamera() {
try {
for (cameraId in cameraManager.cameraIdList) {
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val facing = characteristics.get(CameraCharacteristics.LENS_FACING)
if (facing == CameraCharacteristics.LENS_FACING_FRONT) {
currentCameraId = cameraId
break
}
}
if (currentCameraId == null) {
Log.e(TAG, "No camera found")
return
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), 1)
return
}
Log.i(TAG, "Opening camera: $currentCameraId")
cameraManager.openCamera(currentCameraId!!, stateCallback, mainHandler)
} catch (e: Exception) {
Log.e(TAG, "openCamera error: ${e.message}", e)
}
}