3、环境感知与状态表示:传感器抽象、环境建模方法、状态空间表示、部分可观测环境处理
好,咱们进入第三章。这一章聊的是智能体怎么「看」世界、怎么「理解」世界。
说白了,智能体不是人。它没有眼睛,没有耳朵。它只能靠传感器数据来感知环境。但传感器数据往往是原始、嘈杂、不完整的。怎么把这些乱七八糟的数据变成智能体能用的「状态」?这就是本章要解决的问题。
我在做第一个机器人项目时,就踩过这个坑。传感器数据哗哗地来,我直接拿原始数据去决策,结果机器人像个无头苍蝇。后来才明白——你得先给环境建模,把感知抽象成状态。
3.1 传感器抽象:把物理信号变成信息
传感器种类太多了。摄像头、激光雷达、温度计、麦克风、GPS……每种传感器输出的数据格式都不一样。你不可能为每种传感器都写一套决策逻辑。
所以我们需要「传感器抽象层」。它的作用很简单:把不同传感器的原始数据,统一成智能体能理解的格式。
核心思想: 不管底层是什么传感器,上层只关心「环境中有哪些物体、它们的状态是什么」。
举个例子。一个避障机器人,可能有超声波传感器、红外传感器、激光雷达。传感器抽象层要做的是:
- 读取超声波的距离值(比如 1.2 米)
- 读取红外的障碍物标志(比如 true)
- 读取激光雷达的点云数据
然后统一输出成:{"前方障碍物": true, "距离": 1.2, "置信度": 0.85}
我习惯用接口类来做这件事。定义一个抽象基类,所有传感器都继承它:
class Sensor:
def read(self) -> dict:
"""返回统一格式的感知数据"""
pass
class UltrasonicSensor(Sensor):
def read(self):
distance = self._get_raw_distance()
return {
"type": "distance",
"value": distance,
"unit": "meter",
"confidence": 0.9 if distance < 5 else 0.6
}
class CameraSensor(Sensor):
def read(self):
image = self._capture()
objects = self._detect_objects(image)
return {
"type": "object_list",
"value": objects,
"confidence": 0.75
}
这样做的好处很明显:决策层不用关心你用的是超声波还是激光雷达。它只看到统一的 read() 输出。换传感器?改一行配置就行。
我的经验: 传感器抽象层一定要加「置信度」字段。我在项目中遇到过,超声波在雨天测距完全不准,但代码不知道。加了置信度后,决策层可以忽略低置信度的数据,系统鲁棒性提升了一大截。
3.2 环境建模方法:怎么描述世界
传感器数据来了,但怎么组织这些数据?这就涉及到环境建模。
环境建模,说白了就是用数据结构来描述智能体所处的世界。不同的任务,建模方式完全不同。
我常用的几种建模方法:
3.2.1 栅格地图(Grid Map)
把环境划分成一个个小格子。每个格子标记为「空闲」「占用」「未知」。最适合扫地机器人、自动驾驶的局部路径规划。
grid_map = [
[0, 0, 1, 0, 0],
[0, 1, 1, 0, 0],
[0, 0, 0, 0, 1],
[1, 0, 0, 0, 0]
]
# 0=空闲, 1=占用
3.2.2 拓扑图(Topological Map)
用节点和边来表示环境。节点是「关键位置」(比如房间、路口),边是「连通关系」。适合导航、送货机器人。
graph = {
"A": {"B": 5, "C": 3},
"B": {"A": 5, "D": 2},
"C": {"A": 3, "D": 4},
"D": {"B": 2, "C": 4}
}
3.2.3 语义地图(Semantic Map)
不仅知道「哪里有障碍物」,还知道「那是什么」。比如「这是一张桌子」「那是一把椅子」。适合人机交互、服务机器人。
semantic_map = {
"objects": [
{"type": "table", "position": (2.0, 3.0), "size": (1.2, 0.8)},
{"type": "chair", "position": (2.5, 3.5), "size": (0.5, 0.5)},
{"type": "door", "position": (0.0, 1.0), "state": "open"}
]
}
选型建议: 任务越简单,模型越简单。别一上来就用语义地图。我见过有人给一个「跟着线走」的机器人建了3D点云地图……杀鸡用牛刀了。
3.3 状态空间表示:智能体的「大脑模型」
环境建模完了,但智能体不能直接拿地图去决策。它需要「状态」——也就是当前这一刻,它对环境的完整认知。
状态空间,就是所有可能状态的集合。每个状态,是智能体对环境的「快照」。
举个例子。一个简单的温控智能体:
- 传感器:温度计
- 环境:房间
- 状态:当前温度值(比如 25°C)
- 状态空间:所有可能的温度值(比如 0°C ~ 50°C)
状态表示有两种常见方式:
| 表示方式 | 说明 | 适用场景 |
|---|---|---|
| 离散状态 | 状态是有限的、可枚举的 | 棋类游戏、有限状态机 |
| 连续状态 | 状态是连续的数值 | 机器人控制、自动驾驶 |
| 混合状态 | 部分离散、部分连续 | 大多数真实场景 |
我习惯用字典或类来表示状态:
class RobotState:
def __init__(self):
self.position = (0.0, 0.0) # 连续:位置
self.velocity = 0.0 # 连续:速度
self.battery = 100 # 连续:电量
self.mode = "exploring" # 离散:模式
self.obstacle_detected = False # 离散:是否检测到障碍物
def to_dict(self):
return {
"position": self.position,
"velocity": self.velocity,
"battery": self.battery,
"mode": self.mode,
"obstacle": self.obstacle_detected
}
避坑指南: 状态空间别设计得太大。我曾经给一个导航机器人设计了 50 个状态变量,结果强化学习训练了三天都没收敛。后来砍到 8 个关键变量,半天就搞定了。状态表示要「够用就好」。
3.4 部分可观测环境处理:当你看不到全局
现实世界有个残酷的事实:智能体永远无法获得环境的完整信息。
你想想看,一个自动驾驶汽车,能看到拐角后面的车吗?不能。一个扫地机器人,能知道隔壁房间有没有垃圾吗?不能。
这就是「部分可观测环境」(POMDP)。智能体只能看到环境的一部分,但必须基于不完整的信息做决策。
怎么处理?我常用的方法有四种:
3.4.1 维护信念状态(Belief State)
不直接相信传感器数据,而是维护一个「概率分布」。比如:
- 传感器说「前方有障碍物」,但置信度只有 60%
- 那么信念状态就是:P(有障碍物) = 0.6, P(无障碍物) = 0.4
class BeliefState:
def __init__(self):
self.beliefs = {} # 每个变量的概率分布
def update(self, sensor_data, confidence):
# 贝叶斯更新
for key, value in sensor_data.items():
old_belief = self.beliefs.get(key, 0.5)
new_belief = old_belief * confidence + (1 - old_belief) * (1 - confidence)
self.beliefs[key] = new_belief
def get_most_likely(self):
return {k: v > 0.5 for k, v in self.beliefs.items()}
3.4.2 记忆机制(Memory)
把历史观测存下来。虽然现在看不到,但之前看到过。比如机器人转过弯后,还记得刚才那个房间的布局。
class Memory:
def __init__(self):
self.history = []
def remember(self, state):
self.history.append(state)
if len(self.history) > 100:
self.history.pop(0)
def recall(self, key):
# 从历史中查找某个信息
for state in reversed(self.history):
if key in state:
return state[key]
return None
3.4.3 主动感知(Active Perception)
如果信息不够,就主动去获取。比如机器人停下来,转头看看盲区。或者无人机飞高一点,获得更广的视野。
3.4.4 鲁棒决策(Robust Decision)
实在看不清,就做「最坏情况假设」。比如:不确定前方有没有坑,就默认有坑,绕路走。虽然保守,但安全。
注意: 部分可观测环境下,最忌讳的是「过度自信」。我见过一个案例,机器人只看到半张桌子,就认定「整条路都被堵死了」,结果原地转圈。后来加了信念状态,它知道「可能被堵,也可能没被堵」,决策就灵活多了。
3.5 实战:搭建一个简单的感知-状态流水线
最后,咱们把今天的内容串起来。一个完整的感知-状态流水线长这样:
class PerceptionPipeline:
def __init__(self):
self.sensors = [] # 传感器列表
self.environment_model = None # 环境模型
self.state = None # 当前状态
self.belief = BeliefState() # 信念状态
def add_sensor(self, sensor):
self.sensors.append(sensor)
def step(self):
# 1. 读取所有传感器
raw_data = {}
for sensor in self.sensors:
data = sensor.read()
raw_data.update(data)
# 2. 传感器抽象:统一格式
abstracted = self._abstract(raw_data)
# 3. 更新环境模型
self.environment_model.update(abstracted)
# 4. 更新信念状态(处理部分可观测)
self.belief.update(abstracted, confidence=0.8)
# 5. 生成当前状态
self.state = {
"position": self.environment_model.get_position(),
"obstacles": self.belief.get_most_likely(),
"map": self.environment_model.get_local_map()
}
return self.state
def _abstract(self, raw):
# 抽象逻辑:提取关键信息
return {
"distance": raw.get("ultrasonic", 999),
"objects": raw.get("camera_objects", []),
"battery": raw.get("battery", 100)
}
嗯,这一章内容不少。总结一下:
- 传感器抽象:把原始数据变成统一格式
- 环境建模:用合适的数据结构描述世界
- 状态空间:定义智能体的「认知快照」
- 部分可观测:用信念状态、记忆、主动感知来应对不确定性
下一章,咱们聊决策规划——有了状态,怎么决定下一步做什么。
一句话记住本章: 智能体不是上帝,它只能看到世界的一个小窗口。你的任务,就是帮它把这个小窗口里的信息,变成能用的知识。