• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Realitykit结合Speech实现语音控制AR机器人移动(完整代码)

武飞扬头像
酷酷的崽儿
帮助1

利用Apple最新的Realitykit搭配ARkit实现虚拟物体的放置,结合内置的Speech库实现语音的识别功能,将语音内容转为文本内容,从而让机器进行运动。

大体思路:

1、配置并启动ARkit环境。

2、构建Entity实体。可以用Apple官方的CreatingAPhotogrammetryCommandLineApp的代码文档来生成.usdz文件,从而建造自己想要的实体。

3、放置实体到现实环境中。通过raycast发射射线,通过转化获得现实世界中的x,y,z的坐标,从而把实体放在现实世界中。

4、实现机器人的运动。通过传入文本信息,利用实体的transition属性来进行移动。

5、通过SFSpeechRecognizer获得语音识别允许。

6、创造音频节点,将输入语音的设备设置为麦克风,将音频结果初始化,放到SFSpeechAudioBufferRecognitionRequest里面。

7、进行音频结果的处理,转化为文本,放到机器人运动中。

8、机器人完成运动

没介绍的其他代码就是为实体添加属性,让机器人能够移动,放缩,旋转。

还有一些手势的识别:长按添加新的实体,滑动让实体消失。

  1.  
    import UIKit
  2.  
    import RealityKit
  3.  
    import ARKit
  4.  
    import Speech
  5.  
    class ViewController: UIViewController {
  6.  
    @IBOutlet var arView: ARView!
  7.  
     
  8.  
    var entity: Entity?
  9.  
    var moveToLocation: Transform = Transform()
  10.  
    let moveTime: Double = 5
  11.  
    //语音识别
  12.  
    let speechRecognizer: SFSpeechRecognizer? = SFSpeechRecognizer()
  13.  
    let speechRequest = SFSpeechAudioBufferRecognitionRequest()
  14.  
    var speechTask = SFSpeechRecognitionTask()
  15.  
    // 音频实例化
  16.  
    let audioEngine = AVAudioEngine() //设立音频节点,处理音频输入和输出
  17.  
    let audioSession = AVAudioSession() //音频记录初始化
  18.  
    override func viewDidLoad() {
  19.  
    super.viewDidLoad()
  20.  
    entity = try! Entity.loadModel(named: "toy_robot_vintage.usdz")
  21.  
    entity?.generateCollisionShapes(recursive: true)
  22.  
    //包裹起来 增加碰撞属性
  23.  
    arView.installGestures([.rotation,.scale,.translation], for: entity! as! HasCollision)
  24.  
    //创建session
  25.  
    startARSession()
  26.  
    //创建手势 将2d位置转换为3d位置 获取位置传递到下面的函数中
  27.  
    arView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTapLocation)))
  28.  
    arView.addGestureRecognizer(UISwipeGestureRecognizer(target: self, action: #selector(handleSwipeLocation)))
  29.  
    arView.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressLocation)))
  30.  
    startSpeechRecognition()
  31.  
     
  32.  
    }
  33.  
    @objc func handleTapLocation(_ recognizer:UITapGestureRecognizer){
  34.  
    let tapLocation = recognizer.location(in: arView)
  35.  
    //发射粒子 转化为3d坐标
  36.  
    let result = arView.raycast(from: tapLocation, allowing: .estimatedPlane, alignment: .horizontal)
  37.  
    //得到x,y,z坐标
  38.  
    if let firstResult = result.first{
  39.  
    let worldPosition = simd_make_float3(firstResult.worldTransform.columns.3)
  40.  
    placeModelInWorld(object: entity!, position: worldPosition)
  41.  
    }
  42.  
    }
  43.  
    @objc func handleSwipeLocation(_ recognizer: UISwipeGestureRecognizer){
  44.  
    let longPressLocation = recognizer.location(in: arView)
  45.  
    if let entity = arView.entity(at: longPressLocation){
  46.  
    entity.anchor?.removeFromParent()
  47.  
    }
  48.  
    }
  49.  
    @objc func handleLongPressLocation(_ recognizer: UILongPressGestureRecognizer){
  50.  
    let doubleTapLocation = recognizer.location(in: arView)
  51.  
    let result = arView.raycast(from: doubleTapLocation, allowing: .estimatedPlane, alignment: .horizontal)
  52.  
    //得到x,y,z坐标
  53.  
    if let firstResult = result.first{
  54.  
    let worldPosition = simd_make_float3(firstResult.worldTransform.columns.3)
  55.  
    if (arView.entity(at: doubleTapLocation) == nil){
  56.  
    let objectAnchor = AnchorEntity(world: worldPosition)
  57.  
    let entity1 = try! Entity.loadModel(named: "toy_robot_vintageOne.usdz")
  58.  
    entity1.generateCollisionShapes(recursive: true)
  59.  
    arView.installGestures([.translation,.rotation,.scale], for: entity1)
  60.  
    objectAnchor.addChild(entity1)
  61.  
    arView.scene.addAnchor(objectAnchor)
  62.  
     
  63.  
    }
  64.  
    }
  65.  
    }
  66.  
    func startARSession(){
  67.  
    arView.automaticallyConfigureSession = true
  68.  
    let configuration = ARWorldTrackingConfiguration()
  69.  
    configuration.planeDetection = [.horizontal]
  70.  
    configuration.environmentTexturing = .automatic
  71.  
    // arView.debugOptions = .showAnchorGeometry
  72.  
    arView.session.run(configuration)
  73.  
    }
  74.  
    func placeModelInWorld(object:Entity,position:SIMD3<Float>){
  75.  
    let objectAnchor = AnchorEntity(world: position)
  76.  
    objectAnchor.addChild(object)
  77.  
    arView.scene.addAnchor(objectAnchor)
  78.  
    }
  79.  
    func rebotMove(direction: String){
  80.  
    switch direction{
  81.  
    case "forward":
  82.  
    moveToLocation.translation = (entity!.transform.translation) simd_float3(x:0,y:0,z:20)
  83.  
    entity!.move(to: moveToLocation, relativeTo: entity!, duration: moveTime)
  84.  
    walkAnimation(movementDuration: moveTime)
  85.  
    print("moveForward")
  86.  
    case "back":
  87.  
    moveToLocation.translation = (entity!.transform.translation) simd_float3(x:0,y:0,z:-20)
  88.  
    entity!.move(to: moveToLocation, relativeTo: entity!, duration: moveTime)
  89.  
    walkAnimation(movementDuration: moveTime)
  90.  
    case "left":
  91.  
    let rotateToAngle = simd_quatf(angle: GLKMathDegreesToRadians(90), axis: SIMD3(x:0,y:1,z:0))
  92.  
    entity!.setOrientation(rotateToAngle, relativeTo: entity!)
  93.  
    case "right":
  94.  
    let rotateToAngle = simd_quatf(angle: GLKMathDegreesToRadians(-90), axis: SIMD3(x:0,y:1,z:0))
  95.  
    entity!.setOrientation(rotateToAngle, relativeTo: entity!)
  96.  
    default:
  97.  
    print("没有移动指令")
  98.  
    }
  99.  
    }
  100.  
    func walkAnimation(movementDuration: Double){
  101.  
    if let rebotAnimation = entity!.availableAnimations.first{
  102.  
    entity!.playAnimation(rebotAnimation.repeat(duration: movementDuration),transitionDuration: 0.5,startsPaused: false)
  103.  
    print("Yes")
  104.  
    }else{
  105.  
    print("没有相关动画")
  106.  
    }
  107.  
    }
  108.  
    func startSpeechRecognition(){
  109.  
    //获得允许
  110.  
    requestPermission()
  111.  
    //记录
  112.  
    startAudioRecoding()
  113.  
    //识别
  114.  
    speechRecognize()
  115.  
    }
  116.  
    func requestPermission(){
  117.  
    SFSpeechRecognizer.requestAuthorization { (authorizationStatus) in
  118.  
    if(authorizationStatus == .authorized){
  119.  
    print("允许")
  120.  
    }else if(authorizationStatus == .denied){
  121.  
    print("拒绝")
  122.  
    }else if(authorizationStatus == .notDetermined){
  123.  
    print("等待您的决定")
  124.  
    }else if(authorizationStatus == .restricted){
  125.  
    print("无法启用")
  126.  
    }
  127.  
    }
  128.  
    }
  129.  
    func startAudioRecoding(){
  130.  
    //创造输入节点
  131.  
    let node = audioEngine.inputNode
  132.  
    let recordingFormate = node.outputFormat(forBus: 0)
  133.  
    node.installTap(onBus: 0, bufferSize: 1024, format: recordingFormate) { (buffer, _) in
  134.  
    self.speechRequest.append(buffer)
  135.  
    }
  136.  
    //启动引擎
  137.  
     
  138.  
    do{
  139.  
    //配置音频会话为从麦克风录制
  140.  
    try audioSession.setCategory(.record,mode: .measurement,options: .duckOthers)
  141.  
    try audioSession.setActive(true,options: .notifyOthersOnDeactivation)
  142.  
    audioEngine.prepare()
  143.  
    try audioEngine.start()
  144.  
    }
  145.  
    catch{
  146.  
     
  147.  
    }
  148.  
     
  149.  
    }
  150.  
    func speechRecognize(){
  151.  
    guard let speechRecognizer = SFSpeechRecognizer()else{
  152.  
    print("语音识别不可用")
  153.  
    return
  154.  
    }
  155.  
    if (speechRecognizer.isAvailable == false){
  156.  
    print("无法正常工作")
  157.  
    }
  158.  
    var count = 0
  159.  
    speechTask = speechRecognizer.recognitionTask(with: speechRequest, resultHandler: { (result, error) in
  160.  
    count = 1
  161.  
    if(count == 1){
  162.  
    guard let result = result else {
  163.  
    return
  164.  
    }
  165.  
    let recognizedText = result.bestTranscription.segments.last
  166.  
    self.rebotMove(direction: recognizedText!.substring)
  167.  
    print(recognizedText!.substring)
  168.  
    }else if(count>=3){
  169.  
    count = 0
  170.  
    }
  171.  
    })
  172.  
    }
  173.  
    }
学新通

注释已经放在代码中了,只需要导入自己的.usdz文件就可以运行成功了。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfifheh
系列文章
更多 icon
同类精品
更多 icon
继续加载