简介:面向人工智能初学者与高校相关专业师生的入门课件,以“人工智能与机器人”为主题展开系统讲解。内容从人类智能与人工智能的定义对比切入,明确感知、思维与行为能力在人与机器系统中的不同体现,并解释“为何需要人工智能”的现实动因;主体依次覆盖模式识别、语音识别、图像识别、自然语言理解、机器翻译、机器学习、专家系统与问题求解等方向,其中对语音识别系统的特征提取、声学匹配、语言处理,以及图像识别中先验信息比对等应用细节亦有清晰交代。资源同时梳理了智能机器人从第一代程序控制、第二代自适应到第三代智能化的演进过程,并给出人工智能近期与远期发展目标。整份资源为1个PPTX文件,约4.11MB,结构完整、要点清晰,既适合课堂演示,也便于自学复习。目前已有186人学习浏览,可作为高校人工智能或机器人相关课程配套讲义,帮助读者快速建立AI知识地图。
1. 人工智能与机器人:先解决三层节奏不一致
“人工智能与机器人.pptx”这个名字在项目评审和课程答辩里都很常见,但内容从 PPT 走向真机设备时,最先暴露的不是算法精度,而是感知、决策、执行三层的节奏对不齐。视觉模型按帧输出,推理延迟可能从几十毫秒抖到几百毫秒;任务规划要等上下文,一次决策耗时不可预测;机器人控制器却按 1kHz 插补运动,指令需要在几十毫秒内响应。三层用同步函数硬拼,要么快速层不停覆盖慢层的结果,要么慢层把快层堵在等待队列里。把这三层的职责、接口和失败模式先拆清楚,是让人工智能与机器人协同跑起来的起点。这条链路服务于正在做设备集成的工程师,也适合想从检测 demo 转向上真实机械臂与移动底盘的开发者。
2. 人工智能感知与机器人执行的分工边界与算力选型
2.1 三层分工:感知求最新,决策求可行,执行求确定
人工智能部分承担感知与高层决策,机器人部分承担运动生成与伺服控制,但两层之间必须有一层中间决策,负责把“可能是、大概在、也许可以”变成“是哪个、在哪个、能不能动”。这种分工直接决定算力怎么放。感知层常见选择是本地 GPU 或 NPU 部署轻量化视觉模型,因为实时性和数据私密性都要求低延迟;任务规划可以放在算力更强的边缘服务器,甚至接入大模型做自然语言指令解析;执行层必须跑在机器人控制器或实时内核上,任何一次非确定性阻塞都可能造成碰撞。
这道分界线常常被忽略。给定一个 2D 视觉任务,感知线程在 30ms 到 300ms 之间波动,如果执行线程直接等待同步结果,整条产线的节拍就被最长的推理延迟拖着走。正确做法是让感知层以固定频率产生“最新估计”,让执行层按自己的周期消费最新那一个值,而不是消费每一条结果。机器人导航里的 SLAM 定位、视觉抓取里的目标跟踪,本质上都在用同一个模型处理时间不对齐的问题。
2.2 端到端策略与混合架构的取舍
端到端网络从图像直接输出关节角或速度,看起来简洁,但在真实机器人场景里有三个问题很难绕开。第一是可解释性差,撞了不知道是视觉错还是控制错;第二是数据成本高,工业场景任务单一,数据收集成本远高于一般视觉任务;第三是安全认证无法落地,现有机电安全标准要求确定性行为,端到端输出的概率性质无法直接嵌入急停逻辑。
| 对比项 | 传统规则管线 | 端到端神经网络 | 混合感知-决策-执行 |
|---|---|---|---|
| 实时性 | 确定 | 不确定 | 感知不确定,执行确定 |
| 可调试性 | 高 | 低 | 中,按层定位 |
| 数据需求 | 不需要 | 极大 | 分层后需求大幅下降 |
| 安全策略 | 天然支持 | 难嵌入 | 执行层保留硬保护 |
| 落地周期 | 短但扩展差 | 长,学术演示多 | 适中,产线主流 |
混合架构的要点是分层:感知层输出结构化结果,也就是目标类别、位姿、置信度;决策层在这些结果上做任务规划与可行性检查;执行层只接受结构化指令。这样每一层可以独立测试,感知模型换掉不影响执行逻辑,执行保护逻辑也不受模型升级牵连。实战中的典型形态是 AGV 与机械臂协同:上层调度用 VDA5050 下发任务,机器人导航栈负责路径规划与局部避障,机械臂控制器只执行抓取位姿。每一层都有自己的保护逻辑,AI 层再聪明也不能绕过执行层的软限位和急停回路。
2.3 最小可复现的“最新值覆盖”通信骨架
import multiprocessing as mp import time import random def perception_worker(output_q: mp.Queue): """模拟视觉感知:每 20-80ms 产出一个目标像素坐标""" frame_id = 0 while True: frame_id += 1 x_px = 400 + random.randint(-30, 30) y_px = 300 + random.randint(-30, 30) # 只保留最新一帧,避免执行侧积压旧目标 try: output_q.get_nowait() except Exception: pass output_q.put((frame_id, x_px, y_px)) time.sleep(random.uniform(0.02, 0.08)) def robot_worker(input_q: mp.Queue): """模拟机器人控制:固定 40ms 消费最新目标""" while True: try: frame_id, x_px, y_px = input_q.get(timeout=0.05) except Exception: continue # 暂无可执行目标,等待下一个周期 # 这里做像素到机器人坐标的换算,然后发给控制器 print(f"frame={frame_id} target=({x_px}, {y_px})") time.sleep(0.04) if __name__ == "__main__": q = mp.Queue(maxsize=1) mp.Process(target=perception_worker, args=(q,), daemon=True).start() mp.Process(target=robot_worker, args=(q,), daemon=True).start() time.sleep(5)逻辑说明:感知进程用 get_nowait 把队列里上一帧数据先取走再放入新帧,队列永远只保留最新结果;机器人进程以 0.05 秒超时读取,按 0.04 秒节拍消费。这样即使感知延迟从 20ms 抖动到 80ms,控制侧也不会因为等待推理而停摆,代价是中间帧被丢弃,这在运动控制里是可以接受的,因为机器人要去的永远是“现在的最新位置”。
参数说明:maxsize=1 是“用空间换时序”的关键,队列一旦积压旧目标,执行侧就会追着历史位置跑;get(timeout=0.05) 要小于机器人控制节拍,避免两次消费合并成一次跳变;sleep(0.04) 对应 25Hz 的控制频率,实际项目中要按控制器要求调整,机械臂常见 125Hz 到 1kHz,频率不匹配时会在轨迹上看到明显停顿。
3. 机器人视觉中从像素坐标到运动指令的坐标变换
3.1 为什么模型输出不能直接发给机器人
YOLO 输出的是像素坐标系里的框和类别,机械臂要的是基座标系下的 x/y/z。中间至少经历四个坐标系:像素坐标系、相机坐标系、工具坐标系、机器人基座标系。常见的错误是直接把像素坐标按比例映射成“偏移量”,这种做法在固定安装且深度不变的工位上能跑,一旦相机角度、高度或目标姿态变化,抓取就会偏。
移动机器人导航里有完全一样的问题。激光或视觉 SLAM 输出的是机器人坐标系下的位姿,如果相机到车体外参没标定,地图和路径在数学上对不齐,导航走到一半会出现系统性的定位偏差。外参标定不是可选项,它是摄像头数据能进入运动控制链路的前提。
3.2 两种手眼关系与最小参数集合
手眼关系分两种:眼在手外,相机固定在天花板或支架上;眼在手上,相机装在机械臂末端。两者的标定思路都是求解 AX=XB,但工程实现差别很大,选型直接决定标定流程和误差分配。
| 安装方式 | 相机位置 | 标定核心 | 常见场景 |
|---|---|---|---|
| 眼在手外 | 固定不动 | 相机到机器人基座外参 | 码垛、分拣台、视觉引导定位 |
| 眼在手上 | 装在第六轴 | 相机到工具坐标系外参 | 近距离检测、抓取姿态补偿 |
标定完成后需要保存的最小参数集合是:相机内参(fx, fy, cx, cy,畸变系数),以及相机到机器人基座的外参 4×4 齐次矩阵。内参和畸变通过棋盘格标定得到,外参可以用示教器打点加开源工具求解,也可以借助标定板自动生成。离线仿真环境,比如库卡仿真里,把外参矩阵先验证一遍再上真机,能省掉大量现场对点时间。
3.3 一套可抄的坐标换算 NumPy 代码
import numpy as np # 相机内参,由标定或厂家参数文件给出,单位像素 fx, fy, cx, cy = 615.0, 615.0, 320.0, 240.0 depth = 0.42 # 目标到相机光心的距离,单位米 # 感知模型输出的目标中心(像素坐标) x_px, y_px = 360, 210 # 1. 像素系 -> 相机坐标系 x_cam = (x_px - cx) * depth / fx y_cam = (y_px - cy) * depth / fy z_cam = depth # 2. 相机系 -> 机器人基座标系 T_base_cam = np.load("T_base_cam.npy") # 4x4 齐次矩阵 p_cam = np.array([x_cam, y_cam, z_cam, 1.0]) p_base = T_base_cam @ p_cam # 3. 叠加工具中心点(TCP)偏移后下发 p_target = p_base[:3].copy() p_target[2] -= 0.12 # 吸盘末端在法兰下方 12cm print("TCP target (m):", p_target)逻辑说明:第 1 步用相机内参把像素坐标还原为相机坐标系下的三维点,深度来自深度相机或单目 PnP 求解;第 2 步直接用 4×4 外参矩阵完成旋转和平移,矩阵里最后一行的 0,0,0,1 保证齐次坐标运算成立;第 3 步减去 TCP 在 Z 向的偏移,让控制器收到的位置是工具末端要去的位置,而不是相机观测到的物体表面。
参数说明:fx/fy 跟图像分辨率强相关,模型训练时做 resize 就必须按比例同步修改 cx/cy;depth 单位必须是米,遇到毫米或厘米的接口要先归一化;T_base_cam.npy 在不同手眼模式下含义不同,眼在手上时矩阵要换成相机到工具系的变换,并先转回基座标系再使用。检查外参最直接的办法,是把相机观测到的物体坐标反投影回像素,误差在 2 个像素以内说明标定基本可用。
3.4 现场最容易踩的三个坑
第一个坑是直接用原始像素做变换,没做畸变校正。相机镜头在画面边缘的畸变通常有几个像素,对 0.5m 视场来说就是几毫米的定位误差,抓取小零件时直接超差。第二个坑是分辨率不一致。训练模型时常把 1280×960 缩到 640×480,内参 fx/fy 也必须同步缩放,很多人只改 cx/cy,忘了 fx/fy。第三个坑是把 TCP 偏移加到错误坐标系。工具偏移定义在法兰坐标系,直接叠加到基座标系,会在姿态变化时产生几十毫米的偏差。
排障时如果机器人“进不去系统”或者示教器报控制器通信异常,先查急停回路和示教器接线,再考虑是不是标定参数被覆盖。ABB、库卡、发那科这类控制器都有独立的上电自检流程,多数情况复位后能恢复,不要把视觉标定和控制器启动问题混在一起排查。
4. AI 决策与机器人动作执行之间的异步桥接与安全超时
4.1 同步调用为什么会在长任务上失效
如果只做“拍照-识别-抓取”这样一个固定动作,同步调用模型也能跑通;只要机器人动作耗时超过几秒,问题就来了。调用线程在等待机器人完成期间不能干别的,一旦 AI 推理因为资源抢占变慢,整个节拍就被拖死;如果视觉结果随着物体移动不断更新,同步模型只能执行旧指令,无法响应新目标。
ROS 2 机器人开发里常用三种通信模型:topic 适合高频单向流,service 适合短请求应答,action 适合“要执行几秒甚至更久、还要能中途反馈和取消”的任务。从视觉结果到机械臂运动正是典型的长任务场景,这也是 action 机制在机械臂和移动机器人项目里被普遍采用的原因。VDA5050 一类调度协议在 AGV 场景做的事也类似:调度器下发任务,车端回报状态,任务可以被取消或超时。
4.2 action、service、topic 怎么选
| 通信模型 | 语义 | 适配场景 | 是否适合 AI 到机器人 |
|---|---|---|---|
| topic | 单向发布/订阅,无应答 | 激光点云、图像流、里程计 | 适合感知流,不适合动作任务 |
| service | 请求/应答,一次完成 | 参数读取、开关控制 | 短操作可以,长任务会阻塞 |
| action | goal/feedback/result,可取消 | 导航、机械臂运动、多步骤任务 | 推荐 |
4.3 用 action client 把视觉目标转成机器人运动指令
import rclpy from rclpy.node import Node from geometry_msgs.msg import Pose from custom_msgs.action import MoveToPose # 自定义动作类型 class AIVisionClient(Node): def __init__(self): super().__init__('ai_vision_client') # 动作客户端,连接到机器人控制节点上的同名 action server self._client = self.create_action_client(MoveToPose, 'robot_move') self._timer = self.create_timer(0.5, self.tick) def tick(self): # 每个周期检查是否有新的视觉目标(省略接收代码) target = self.latest_target() if target is None: return goal = MoveToPose.Goal() goal.target_pose.position.x = float(target[0]) goal.target_pose.position.y = float(target[1]) goal.target_pose.position.z = float(target[2]) # 异步发送,不阻塞 AI 线程 send_future = self._client.send_goal_async( goal, feedback_callback=self.on_feedback) send_future.add_done_callback(self.on_goal_accepted) def on_feedback(self, feedback_msg): # 机器人回报当前进度,记录时间戳用于时延分析 self.get_logger().info(f"progress: {feedback_msg.feedback.progress:.1%}") def on_goal_accepted(self, future): goal_handle = future.result() if not goal_handle.accepted: self.get_logger().warn("goal rejected, 目标不可达") return result_future = goal_handle.get_result_async() result_future.add_done_callback(self.on_result) def on_result(self, future): result = future.result().result self.get_logger().info(f"finished, error={result.error_code}")逻辑说明:send_goal_async 把目标交给执行节点后立即返回,AI 线程可以继续处理下一帧,不用等机械臂走完整个轨迹;feedback 回调在每个控制周期收到进度;goal 被拒绝表示执行层可行性检查不过,常见于目标位姿超出工作空间,或机器人状态机处于安全保护态。
参数说明:create_timer(0.5) 是视觉目标检查周期,不能小于相机帧率,否则会重复发送同一个目标;feedback 回调里记录时间戳,是后续双通道日志分析的数据来源;goal 取消需要额外调用 cancel_goal_async,在物体移动或更高优先级指令抢占时使用。
4.4 超时、重试与安全优先级
| 参数 | 建议值 | 说明 |
|---|---|---|
| wait_for_server | 3-5 秒 | 控制器节点准备好之前不应发送 |
| goal 执行超时 | 任务预估 ×1.5 | 不可靠的目标会拖死队列 |
| 最大重试 | 3 次 | 连续失败要转人工介入 |
| 安全信号优先级 | E-stop > 碰撞 > 超时 | AI 永远不能覆盖硬保护 |
提示:当动作执行超过最长等待时间,先做安全停车,再走重试分支。重试只能用于“目标经过可行性检查但网络抖动导致失败”的情形,不能用于触碰限位或急停触发的故障。
4.5 运行监控与告警通道
运行监控里最容易漏掉的是 AI 侧的置信度变化。目标短暂丢失时,常见做法是让机器人停在原地等待 N 帧而不是立刻取消目标;连续 N 帧都丢,AI 层要发“目标丢失”事件,由决策层决定是否重新规划,而不是把上一次的坐标再发一次。执行侧的错误码和 AI 侧的 goal 编号要写进同一条事件记录,告警推到飞书群或企业微信群时带上这个编号,值班的人能直接查日志,而不是截一张图让现场去猜。
5. 用双通道日志回放定位人工智能与机器人协作故障
5.1 统一任务 ID 的日志格式
AI 侧日志与机器人侧日志必须共用一个任务编号,否则两侧进程各记各的时间,故障只能靠肉眼猜。实际做法是:AI 检测到目标后生成 goal#003 这种全局递增编号,后续所有日志都带这个编号。AI 侧在“检测到目标”和“发送成功”各写一条,机器人侧在“接受目标”“执行反馈”“最终结果”各写一条,时间戳统一精确到毫秒。
[2025-03-01 10:00:01.123] [AI] goal#003 pick -> pose(0.42, 0.18, 0.25) [2025-03-01 10:00:01.145] [ROBOT] goal#003 accepted, start move [2025-03-01 10:00:01.733] [ROBOT] goal#003 feedback 45% [2025-03-01 10:00:02.050] [ROBOT] goal#003 result success, err_code=0有了编号,才能区分“AI 没有检测到”和“AI 检测到了但没发出去”这两种完全不同的问题。
5.2 用 bash 合并两路日志的时间线
# 提取带 goal# 的记录,时间转 epoch 毫秒后按全局时间排序 { cat ai.log robot.log; } | \ sed -nE 's/^\[([0-9-]+ [0-9:.]+)\].*goal#([0-9]+).*/\1 \2/p' | \ while read ts gid; do printf "%s %s\n" "$(date -d "$ts" +%s%3N)" "$gid" done | sort -n逻辑说明:sed 从两路日志里抽出“时间戳+任务编号”两列,date 转成 epoch 毫秒,sort 按数值排序后就得到全局时间线。接着按任务编号回放,偏差一眼就能看出是通信延迟、执行延迟,还是 AI 根本没有输出。
参数说明:date -d 依赖系统时区,控制柜和工控机必须做 NTP 同步,否则排序结果没有参考价值;跨天日志要在时间戳里带日期,只带时分秒在跨 0 点时会排错。
5.3 典型故障特征与定位表
| 故障现象 | 优先排查层 | 检查点 |
|---|---|---|
| AI 有日志,机器人无 accepted | 通信层 | action 服务名、等待超时 |
| 已 accepted 但一直无 result | 执行层 | E-stop、碰撞、工作空间限制 |
| result 频繁 error | 坐标层 | 外参矩阵、TCP 偏移、深度值单位 |
| goal 重复下发 | 决策层 | 目标去重、置信度阈值、丢失后重新跟踪 |
5.4 给日志加 phase 字段,一次回放看出瓶颈
只靠时间戳排序仍然要人肉看每一行。更好的做法是在 AI 侧日志里直接写下感知阶段耗时,机器人侧在 result 里回报执行耗时,通信耗时则等于“机器人 accepted 时间戳”减去“AI 发送时间戳”。三条时间差相加,就得到一次任务的完整耗时构成。
排障时直接看 phase 占比:感知耗时远大于执行,去查模型推理和图像队列;通信耗时异常大,去查网络和服务端线程数;执行耗时波动大,优先查工作空间的障碍物和速度规划参数。这套双通道日志加上阶段拆分,比在仿真里反复回放更能暴露真实产线上的时序问题。
本文还有配套的精品资源,点击获取