为机器人提供知觉

为机器人提供知觉

为机器人和AI代理提供有效的感知能力是开发智能系统的关键挑战。本章将探讨如何在Unity中实现机器人感知系统,包括障碍物检测和环境记忆功能,使AI能够更好地理解和导航其所处的环境。

8.1 回避障碍物

障碍物检测和回避是任何移动机器人或AI代理必须具备的基本能力。在游戏和模拟环境中,这些技术让AI角色能够自然、智能地在复杂环境中移动。

csharp

using UnityEngine;
using System.Collections.Generic;

/// <summary>
/// 基础障碍物感知和回避系统
/// </summary>
public class ObstacleAvoidance : MonoBehaviour
{
    [Header("感知设置")]
    public float detectionRadius = 5.0f;
    public float detectionAngle = 120.0f;
    public int rayCount = 8;
    public LayerMask obstacleLayer;
    
    [Header("移动设置")]
    public float moveSpeed = 3.0f;
    public float rotationSpeed = 120.0f;
    public float avoidanceWeight = 1.5f;
    public float targetWeight = 1.0f;
    
    [Header("目标设置")]
    public Transform target;
    
    // 调试可视化
    public bool showDebugRays = true;
    
    // 存储探测结果
    private List<RaycastHit> detectedObstacles = new List<RaycastHit>();
    private Vector3 avoidanceDirection = Vector3.zero;
    private Vector3 targetDirection = Vector3.zero;
    
    void Update()
    {
        // 清除上一帧的探测结果
        detectedObstacles.Clear();
        
        // 探测周围障碍物
        DetectObstacles();
        
        // 计算回避方向
        CalculateAvoidanceDirection();
        
        // 计算朝向目标的方向
        CalculateTargetDirection();
        
        // 计算最终移动方向
        Vector3 moveDirection = (avoidanceDirection * avoidanceWeight + 
                                targetDirection * targetWeight).normalized;
        
        // 应用移动
        Move(moveDirection);
    }
    
    /// <summary>
    /// 检测周围的障碍物
    /// </summary>
    void DetectObstacles()
    {
        // 围绕角色发射射线
        for (int i = 0; i < rayCount; i++)
        {
            float angle = transform.eulerAngles.y - detectionAngle/2 + 
                         (detectionAngle * i / (rayCount - 1));
            
            // 将角度转换为方向向量
            Vector3 direction = Quaternion.Euler(0, angle, 0) * Vector3.forward;
            
            // 发射射线
            RaycastHit hit;
            if (Physics.Raycast(transform.position, direction, out hit, 
                               detectionRadius, obstacleLayer))
            {
                // 记录检测到的障碍物
                detectedObstacles.Add(hit);
                
                // 绘制调试射线
                if (showDebugRays)
                    Debug.DrawLine(transform.position, hit.point, Color.red);
            }
            else if (showDebugRays)
            {
                // 绘制未检测到障碍物的射线
                Debug.DrawRay(transform.position, direction * detectionRadius, Color.green);
            }
        }
    }
    
    /// <summary>
    /// 根据检测到的障碍物计算回避方向
    /// </summary>
    void CalculateAvoidanceDirection()
    {
        // 如果没有检测到障碍物,则不需要回避
        if (detectedObstacles.Count == 0)
        {
            avoidanceDirection = Vector3.zero;
            return;
        }
        
        // 计算回避向量
        Vector3 avoidance = Vector3.zero;
        
        foreach (RaycastHit hit in detectedObstacles)
        {
            // 计算从障碍物到角色的方向
            Vector3 fromObstacle = transform.position - hit.point;
            
            // 回避力与距离成反比
            float weight = 1.0f - (hit.distance / detectionRadius);
            
            // 累加加权回避向量
            avoidance += fromObstacle.normalized * weight;
        }
        
        // 正规化回避方向
        avoidanceDirection = avoidance.normalized;
        
        // 绘制回避方向
        if (showDebugRays && avoidanceDirection != Vector3.zero)
        {
            Debug.DrawRay(transform.position, avoidanceDirection * 2, Color.yellow);
        }
    }
    
    /// <summary>
    /// 计算朝向目标的方向
    /// </summary>
    void CalculateTargetDirection()
    {
        if (target != null)
        {
            targetDirection = (target.position - transform.position).normalized;
            
            // 绘制目标方向
            if (showDebugRays)
            {
                Debug.DrawRay(transform.position, targetDirection * 2, Color.blue);
            }
        }
        else
        {
            targetDirection = transform.forward;
        }
    }
    
    /// <summary>
    /// 根据计算的方向移动角色
    /// </summary>
    /// <param name="direction">移动方向</param>
    void Move(Vector3 direction)
    {
        // 朝向目标方向旋转
        if (direction != Vector3.zero)
        {
            Quaternion targetRotation = Quaternion.LookRotation(direction);
            transform.rotation = Quaternion.RotateTowards(
                transform.rotation, 
                targetRotation, 
                rotationSpeed * Time.deltaTime
            );
        }
        
        // 向前移动
        transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
    }
    
    /// <summary>
    /// 设置导航目标
    /// </summary>
    /// <param name="newTarget">新的目标变换</param>
    public void SetTarget(Transform newTarget)
    {
        target = newTarget;
    }
    
    /// <summary>
    /// 在编辑器中可视化检测范围
    /// </summary>
    void OnDrawGizmosSelected()
    {
        // 绘制检测半径
        Gizmos.color = Color.cyan;
        
        // 绘制扇形检测区域
        Vector3 leftRay = Quaternion.Euler(0, -detectionAngle/2, 0) * Vector3.forward;
        Vector3 rightRay = Quaternion.Euler(0, detectionAngle/2, 0) * Vector3.forward;
        
        Gizmos.DrawLine(transform.position, transform.position + leftRay * detectionRadius);
        Gizmos.DrawLine(transform.position, transform.position + rightRay * detectionRadius);
        
        // 绘制半圆弧
        int segments = 20;
        Vector3 prev = transform.position + leftRay * detectionRadius;
        
        for (int i = 1; i <= segments; i++)
        {
            float angle = -detectionAngle/2 + (detectionAngle * i / segments);
            Vector3 direction = Quaternion.Euler(0, angle, 0) * Vector3.forward;
            Vector3 current = transform.position + direction * detectionRadius;
            
            Gizmos.DrawLine(prev, current);
            prev = current;
        }
    }
}

这个基础障碍物回避系统使用射线检测来感知周围环境,并根据检测结果计算回避方向。它还考虑了导航目标,通过平衡回避力和目标吸引力来确定最终移动方向。该系统具有良好的可视化功能,便于调试和优化。

8.1.1 探测环境

为了有效地感知环境,我们需要实现更先进的探测技术。以下是一个增强版的环境探测系统,它使用多种传感器模拟来提供更全面的环境感知:

csharp

using UnityEngine;
using System.Collections.Generic;

/// <summary>
/// 高级环境探测系统,模拟多种传感器
/// </summary>
public class EnvironmentSensor : MonoBehaviour
{
    [System.Serializable]
    public class SensorReading
    {
        public float distance;
        public Vector3 hitPoint;
        public Vector3 hitNormal;
        public GameObject hitObject;
        public float angle;
    }
    
    [Header("传感器配置")]
    public enum SensorType
    {
        Raycast,
        Spherecast,
        Overlap
    }
    
    [System.Serializable]
    public class Sensor
    {
        public string name = "Sensor";
        public SensorType type = SensorType.Raycast;
        public Vector3 localPosition;
        public Vector3 localDirection = Vector3.forward;
        public float distance = 5.0f;
        public float radius = 0.5f;
        public LayerMask detectionLayer;
        public Color debugColor = Color.green;
        public bool drawDebug = true;
        
        [HideInInspector]
        public SensorReading lastReading = new SensorReading();
    }
    
    public List<Sensor> sensors = new List<Sensor>();
    
    [Header("高级探测设置")]
    public bool enableDynamicDetection = true;
    public float scanFrequency = 10f;
    public bool detectMaterials = false;
    public bool detectMovingObjects = true;
    
    // 存储环境数据
    public Dictionary<int, SensorReading> sensorData = new Dictionary<int, SensorReading>();
    private float scanTimer = 0f;
    
    void Start()
    {
        // 初始化传感器数据
        for (int i = 0; i < sensors.Count; i++)
        {
            sensorData[i] = new SensorReading();
        }
    }
    
    void Update()
    {
        // 定时扫描环境
        if (enableDynamicDetection)
        {
            scanTimer += Time.deltaTime;
            
            // 根据扫描频率进行检测
            if (scanTimer >= 1f / scanFrequency)
            {
                ScanEnvironment();
                scanTimer = 0f;
            }
        }
    }
    
    /// <summary>
    /// 扫描环境
    /// </summary>
    public void ScanEnvironment()
    {
        for (int i = 0; i < sensors.Count; i++)
        {
            // 执行传感器检测
            SensorReading reading = ScanWithSensor(sensors[i]);
            
            // 更新传感器数据
            sensors[i].lastReading = reading;
            sensorData[i] = reading;
        }
        
        // 执行特殊环境检测
        if (detectMovingObjects)
        {
            DetectMovingObjects();
        }
    }
    
    /// <summary>
    /// 使用单个传感器进行扫描
    /// </summary>
    SensorReading ScanWithSensor(Sensor sensor)
    {
        SensorReading reading = new SensorReading();
        reading.distance = sensor.distance;
        
        // 传感器的世界坐标和方向
        Vector3 sensorPosition = transform.TransformPoint(sensor.localPosition);
        Vector3 sensorDirection = transform.TransformDirection(sensor.localDirection).normalized;
        
        bool hitDetected = false;
        
        // 根据传感器类型执行不同的检测
        switch (sensor.type)
        {
            case SensorType.Raycast:
                RaycastHit rayHit;
                if (Physics.Raycast(sensorPosition, sensorDirection, out rayHit, 
                                   sensor.distance, sensor.detectionLayer))
                {
                    reading.distance = rayHit.distance;
                    reading.hitPoint = rayHit.point;
                    reading.hitNormal = rayHit.normal;
                    reading.hitObject = rayHit.collider.gameObject;
                    hitDetected = true;
          
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小宝哥Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值