ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

RoboCup仿真2D从源码到上场:agent2d编译与连接全攻略

RoboCup仿真2D从源码到上场:agent2d编译与连接全攻略 第一次把 Agent2D 的源码编译出可执行文件、然后看着 11 个自带编号的小球员在同一台机器上连进 rcssserver 时我才真正理解 RoboCup 仿真2D 的“球队”不过是一堆遵守同一套通信协议的进程。很多新手卡在这个环节教程只说到“下载源码”“编译”却没解释为什么要先编 librcsc、为什么 configure 老提示缺库、为什么明明编译成功却连不上服务器。这篇笔记是我自己在踩过一轮坑之后整理的完整流程覆盖从源码到上场的全链路编译原理层面的理解、Linux 下常用构建工具的使用、上场必须知道的 server-client 关系以及一份可以直接照抄的自动开赛脚本。适合已经装好 Ubuntu、了解 rcssserver 基本概念、但还没把任何一支球队代码跑起来的同学。看完你应该能做到三件事独立编译 agent2d 系列代码让 11 个 agent 连进服务器并在 monitor 里看到一场真实的仿真比赛。1. 编译与上场到底在解决什么问题1.1 为什么球队代码不是“双击就能跑”很多第一次接触 RoboCup 仿真2D 的人会下意识把它理解成一个游戏下载个客户端点开就能踢球。但实际不是这样。参赛队伍本质上是一个个自主决策的程序程序用 C 等语言写成经过编译后生成 Linux 可执行文件比赛服务器 rcssserver 只认这些可执行文件通过标准 socket 发来的指令它不会直接解读你的源码。所以“编译”是横在源码和比赛之间的一道必要工序。它把几百个 .cpp、.h 文件变成机器可执行的二进制这个二进制才是你球队真正的“本体”。编译不好后面所有工作都无从谈起。我见过不少人卡在“编译通过但上场失败”的中间地带代码确实生成了可执行文件但因为依赖库没装对、链接阶段出错程序一跑就崩或者压根无法和服务器建立连接。因此第一篇笔记往往讲环境准备第二篇必须把编译和上场这条主线打通。1.2 “上场”本质上是网络连接“上场”这个词听起来像体育比赛里的换人但在仿真2D里它其实是一次标准的网络通信过程。比赛服务器启动后会监听一个 TCP 端口默认是 6000。你的球队代码运行后每个球员都是一个独立的客户端进程它们需要主动连接到这个端口然后用约定的协议完成注册告诉服务器自己属于哪个队、是几号球员。也就是说球队代码编译完只是拿到了“入场券”真正上场还需要做三件事启动 rcssserver 比赛服务器让它进入等待状态。启动 11 个 agent 进程设置好队伍名、服务器地址、端口和球员编号。打开监控器monitor确认 11 个球员成功注册并进入场地。理解这一点非常关键。因为很多“上场失败”的报错比如Connection refused、Sorry, the server is full、球员连上又立刻退出本质上都不是代码逻辑问题而是网络连接、端口占用、球员编号冲突这些基础环节没做好。先把通信链路搞明白再回去调战术你才不会在错误的层面浪费时间。1.3 从源码到一场比赛的完整链路把整个流程画成一条线会清晰很多。我建议新手先对着这条链路把每个环节跑通一次后面再逐步替换成自己的代码下载并解压 agent2d 源码通常连带 librcsc 依赖库一起。编译 librcsc 静态库并安装到系统目录。编译 agent2d 主程序生成可执行文件。启动 rcssserver 服务器指定端口号。用脚本启动 11 个 agent 进程并传入队伍名、地址、端口、编号参数。打开 soccerwindow2 或 rcssmonitor连接同一服务器观战。比赛结束后查看生成的日志文件用 logplayer 回放分析。这篇文章会按这条链路一步步展开。源码可以在官方或教学社区下载下面所有路径都以常见的 agent2d-3.1.1 加 librcsc-4.1.0 组合为例不同版本目录结构可能略有差异但核心思路一致。2. 编译之前环境、源码结构与编译原理2.1 先把依赖装齐别让环境拖后腿在开始编译之前我强烈建议先把系统依赖一次性装好。很多编译报错根本不是代码问题而是缺了某个头文件或库。以 Ubuntu 20.04 / 22.04 为例我用的是这一套sudo apt update sudo apt install build-essential autoconf automake libtool pkg-config sudo apt install libboost-all-dev libssl-dev libsdl2-dev qtbase5-dev sudo apt install rcssserver rcssmonitor简单说下每个包的作用。build-essential是必装的它包含 gcc、g、make 等基础编译工具没有它你连 configure 这一步都跑不完。autoconf、automake、libtool是用来生成和运行 configure 脚本的agent2d 和 librcsc 都依赖这套构建系统。pkg-config用来在 configure 阶段查找已安装的库后面经常用到。libboost-all-dev是 agent2d 的硬依赖代码里大量使用了 Boost 的智能指针、线程、随机数等组件。rcssserver和rcssmonitor分别是比赛服务器和官方监视器如果你不想装监控器也可以只装 rcssserver然后用 agent2d 自带的 soccerwindow2。这些包装完后可以用g --version和make --version验证一下编译器环境。如果系统里同时存在多个 gcc 版本最好确认一下默认版本后面编译遇到奇怪报错时版本因素要纳入排查范围。2.2 看懂源码目录agent2d 和 librcsc 是什么关系下载并解压 agent2d 后你会看到类似这样的目录结构agent2d-3.1.1/ ├── bin/ ├── src/ ├── config/ ├── librcsc-4.1.0/ ├── configure ├── Makefile.in └── ...其中src目录存放的是 agent2d 主程序源码也就是球员决策逻辑。librcsc-4.1.0是另一个独立的源码库全称是 RoboCup Soccer Simulation 基础库封装了世界模型解析、底层动作接口、几何计算等通用功能。agent2d 的代码依赖 librcsc就像一辆整车依赖发动机和底盘你没法只编译车身就跑起来。所以编译顺序必须是先编译 librcsc再编译 agent2d。librcsc 编译后会生成静态库文件比如librcsc.aagent2d 在链接阶段需要用到它。这里有个新手容易踩的坑如果你先编译 agent2dconfigure 会明确报错说找不到 librcsc这是正常的说明依赖顺序不对不是你的系统坏了。另外还要注意bin目录编译成功后生成的可执行文件 agent2d、soccerwindow2 都会放在这里。很多教程默认你知道这个位置但第一次找的人经常盯着src翻半天还找不到可执行文件在哪。2.3 编译原理小课configure、make、链接器到底在干嘛市面上讲编译原理的书动辄几百页但对我们编译球队代码来说只需要建立三层心理模型。第一层是 configure。它是发行版作者写好的一堆 shell 脚本作用是在你的机器上“体检”检查 g 版本、检查 Boost 库位置、检查 librcsc 是否已经安装然后根据检测结果生成对应的 Makefile。所以每次换环境、换机器后最稳妥的做法是重新跑一次 configure而不是拿着旧 Makefile 硬编译。第二层是 make。make 读取 Makefile 里的规则把一个个.cpp源文件编译成.o目标文件。这个过程很像“一道菜分步骤做”先把菜洗好、切好编译最后再下锅炒链接。源文件很多时make -j4可以同时开 4 个任务明显缩短等待时间。但第一次编译时我建议先用单线程跑一遍这样报错信息不会混在一起容易定位问题。第三层是链接。目标文件被链接器拼成一个可执行文件同时把用到的外部库的二进制代码绑定进来。如果你看到undefined reference to xxx说明某个函数声明了但没找到定义大概率是链接时缺了某个库或者库的链接顺序不对。常见做法是在 Makefile 的LIBS变量里加上对应的-l参数。这块知识看起来偏理论但实际排查编译错误时特别管用。把这三层搞明白再遇到编译报错就不会像看天书了configure 报错看环境编译阶段报错看语法和头文件链接阶段报错看库和符号。3. 亲手把球队代码编译出来3.1 先编译基础依赖库 librcsc打开终端进入 librcsc 源码目录依次执行cd /path/to/agent2d-3.1.1/librcsc-4.1.0 ./configure make这一步会生成 librcsc 的静态库文件。如果一切顺利你会在源码目录下看到src或对应目录里多了一个.a文件比如librcsc.a。这个文件就是后面 agent2d 链接时需要的“原材料库”。这里有个容易忽略的细节agent2d 的 configure 脚本默认会通过pkg-config去系统路径寻找 librcsc所以如果你只是编译了 librcsc但没有安装到系统目录下一步 configure agent2d 时它依然会提示找不到库。最简单的做法是接着输入sudo make install这条命令会把 librcsc 的头文件和库文件复制到/usr/local/include、/usr/local/lib等系统目录下同时更新 pkg-config 的元数据文件。装完后最好执行一次sudo ldconfigldconfig用来刷新动态链接器的缓存如果后面链接阶段报错说找不到共享库八成是你忘了这一步。需要说明的是这一步不是标准文档里一定会写的而是我实际编译时踩过坑后发现的很多教程只说“编译 librcsc”没提 install结果在编译 agent2d 时会被 configure 卡住半天报错信息五花八门特别劝退新手。3.2 编译主程序 agent2d基础库解决后回到 agent2d 顶层目录执行cd /path/to/agent2d-3.1.1 ./configure make如果没有报错编译完成后检查bin目录ls -l bin/你会看到至少以下几个文件agent2d、soccerwindow2有的版本还会附带start.sh或test.sh。到这一步你已经把球队代码从源码变成了可执行程序这是从“零”到“能跑”最关键的一步。如果 configure 阶段报错说找不到 librcsc而你已经安装了 librcsc但安装到了非默认前缀目录就需要手动指定搜索路径。常见的做法是设置环境变量export PKG_CONFIG_PATH/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH export LD_LIBRARY_PATH/usr/local/lib:$LD_LIBRARY_PATH然后重新跑 configure。这类环境变量问题的核心原因是系统默认找不到库的位置把路径明确指给它即可。我要特别强调一个细节不要看到 configure 报错就开始百度“如何卸载重装”先想想这个库是不是已经装了、只是路径没对上。百分之九十的 configure 失败都是这个问题。3.3 验证编译成果编译成功的标准不是“没有报错”而是可执行文件能正常响应。先跑一下帮助命令./bin/agent2d --help正常情况下会输出一长串启动参数其中你会看到-h指定服务器主机、-p指定端口、-t指定队伍名、-n指定球员编号。这些参数稍后上场时会用到。同理./bin/soccerwindow2 --help也可以用来验证监控器程序是否可用。我在第一次编译时犯过一个低级错误以为 make 结束看到提示符就完事了结果直接运行./agent2d却发现根本没这个文件原来可执行文件在bin目录下。这种目录习惯问题很常见多花一分钟看一下生成物在哪里比瞎猜命令要靠谱得多。3.4 编译加速与编译期异常排查编译 agent2d 这类项目第一次全量编译大概要几分钟和你在搜索引擎里看到的“keil5 编译很慢”等现象是同一个道理编译器要逐个处理每个源文件文件越多耗时越长。如果你有信心环境没问题可以直接用make -j4-j后面的数字是并行编译的任务数一般取 CPU 核心数或核心数加一。我自己的机器是 8 核用-j8能把编译时间压缩到一分钟左右。但注意如果项目本身就依赖严格的编译顺序并行反而会出错遇到诡异问题就退回单线程看看报错。如果你希望生成调试版本方便之后用 gdb 跟踪可以在 configure 时加上./configure --enable-debug或者在 make 时覆盖编译参数make CXXFLAGS-O0 -g -stdc11这里的-O0禁止优化、-g生成调试信息、-stdc11指定语言标准。后面调试球员异常崩溃时调试版本比发布版本有用很多。需要提醒的是修改了编译参数后最好先make clean清掉旧的目标文件再重新 make否则可能出现新旧代码混用导致的诡异行为。4. 上场11 个球员怎么连上服务器4.1 先把比赛服务器跑起来编译工作结束后进入上场环节。第一步是启动 rcssserver。打开一个终端窗口输入rcssserver -p 6000 -p参数指定服务器监听的端口默认就是 6000这里显式写出来是为了让你知道有这个参数。加让它后台运行这样你还能在同一终端里继续输命令对于新手特别方便。启动后最好确认一下端口确实在监听。我习惯用netstat -tlnp | grep 6000或者用ss -tlnp | grep 6000。如果看不到监听记录说明服务器没起来或者端口被其他程序占用了。可以用ps aux | grep rcssserver确认进程状态。服务器启动后不会立刻开踢它处于“等待客户端连接”的状态。接下来要让你的球队连进去。这一步我用了一个很形象的比喻服务器就是足球场的大门agent 就是排队进场的球员每个球员报到时要说清自己是哪个队、几号。4.2 手动一条条启动 agent先跑明白再谈自动化先用手动方式启动第一个球员理解每个参数的含义./bin/agent2d -t myteam -h 127.0.0.1 -p 6000 -n 1解释一下这些参数-t myteam队伍名。同一支球队的 11 个球员必须使用相同的队伍名服务器根据队伍名区分对阵双方。-h 127.0.0.1服务器地址。本地比赛直接填本机回环地址即可如果服务器在另一台机器上要填那台机器的 IP。-p 6000服务器端口必须和 rcssserver 启动时一致。-n 1球员编号范围一般是 1 到 11。服务器会根据编号分配初始站位比如 1 号通常是守门员位置。手动启动 1 个球员后打开 monitor 看看他是否在场上。接着用同样的命令依次启动 2 号、3 号……直到 11 号。但你会立刻发现手动方式太繁琐了而且每个终端被进程占着很不方便。所以对上场流程熟悉后就要切换到脚本方式。补充一个常见错误如果你启动两个同编号球员后一个通常会失败或把前一个挤掉因为服务器不允许相同队伍、相同编号的两个球员同时注册。新手用脚本循环时很容易因为循环变量问题反复启动同一个编号排查时第一个怀疑对象就是它。4.3 自动开赛脚本一分钟让11个球员全部上场这是我个人非常推荐的做法。写一个简单的 shell 脚本一次性启动 11 个 agent同时把每个进程的输出日志分别保存下来方便之后排查问题。脚本内容如下#!/bin/bash TEAMmyteam SERVER_HOST127.0.0.1 PORT6000 AGENT_BIN./bin/agent2d LOG_DIR/tmp/myteam_logs mkdir -p $LOG_DIR for i in $(seq 1 11); do $AGENT_BIN -t $TEAM -h $SERVER_HOST -p $PORT -n $i \ $LOG_DIR/agent_${i}.log 21 sleep 0.2 done echo 11 agents launched. PID of this script: $$脚本逻辑很简单从 1 循环到 11每个编号启动一个 agent 进程标准输出和错误输出都重定向到独立的日志文件。sleep 0.2是为了避免 11 个进程同时请求连接给服务器造成压力实际测试下来这个间隔比较合适。停止比赛时可以用pkill -f agent2d或者精确一点先ps aux | grep agent2d找到进程号再kill。我建议用精确方式避免误杀其他无关进程。agent2d 源码里通常也自带了类似的启动脚本比如bin/start.sh不同版本内容会有些差异。自己手写一遍脚本的好处是你能真正理解服务器、客户端、参数之间的对应关系后面换代码、换队伍名、调整端口时都能自己改而不是依赖别人的脚本。4.4 用 monitor 看实时比赛再用日志复盘球员全部连接成功后就可以打开监控器看比赛了。如果你的 agent2d 编译成功可以直接运行自带的./bin/soccerwindow2它启动后会通过图形界面让你选择连接哪个服务器、端口也可以直接传参指定./bin/soccerwindow2 -h 127.0.0.1 -p 6000如果你安装的是官方 rcssmonitor用法也是类似的。连接成功后你会看到场地上的蓝色小圆点那是你的球员如果对手也已经连接会看到另一个颜色的圆点。此时服务器正常发球、计时一场仿真比赛就真正跑起来了。比赛结束后rcssserver 一般会在运行目录下生成日志文件比如.rcg和.rcl分别记录比赛过程和通信命令。用 agent2d 自带的 rcsslogplayer 可以回放这些日志方便你复盘某个回合的决策。刚开始不要求看得很细但至少要知道日志文件存在后面调队形、调策略时会频繁用到。5. 常见问题与排错技巧5.1 编译环节问题速查表这一节把我见过的编译错误整理成速查表遇到类似报错可以直接按表格排查。很多报错看着不一样根因其实是同一个。错误现象可能原因解决办法configure: error: C compiler cannot create executablesg 没装全或版本异常重新安装 build-essential检查 g 版本fatal error: boost/xxx.hpp: No such file or directory缺少 Boost 头文件安装 libboost-all-devconfigure: error: could not find librcsclibrcsc 未编译安装或 pkg-config 路径不对先编译 librcsc 并 sudo make install再设置 PKG_CONFIG_PATHundefined reference to xxx链接阶段找不到某个函数定义检查 Makefile 的 LIBS确认对应库已安装且链接顺序正确make: g: No such file or directory编译器未安装或 PATH 环境变量异常安装 build-essential检查 g 是否可用std::xxx has not been declared编译器默认标准太老在 CXXFLAGS 中加 -stdc11 或更高版本其中“undefined reference”是我见过最劝退新手的错误。它发生在编译后期前面的源文件都顺利通过了只有链接时符号对不上。解决方案通常是检查 Makefile 里链接库的名字和顺序。GNU 链接器对静态库顺序很敏感被依赖的库要放在依赖方的后面。agent2d 这种情况-lrcsc一般要放在源文件之后。5.2 上场连接问题速查表编译通过了不代表能上场。连接阶段的问题更细碎单独列一张表错误现象可能原因解决办法Connection refused服务器没启动或端口填写错误用 netstat 确认 rcssserver 监听端口核对 -p 参数球员启动后立刻退出无输出参数缺失或无效在终端前台运行单个 agent观察直接输出同编号球员被踢下线相同 team 下重复注册同一编号检查脚本循环变量确保 1-11 只启动一次monitor 里看不到球员monitor 连接的服务器端口不对或球员没注册成功确认 monitor、agent、server 三者都指向同一个 ip:port比赛没开始一直等待开球双方球员数量不足或服务器等待 kick_off 指令确认对阵双方总球员数足够检查日志是否出现 kick_off看到Connection refused时第一反应不要猜测是否有代理或防火墙也不要在这类问题上纠缠先确认最基础的链路服务器进程在不在、端口是否监听、地址是否写对。我试过在服务器还没启动时就运行 agent结果一片红字当时还以为是代码坏了后来冷静下来才想起 server 根本没开。5.3 实用调试三板斧日志、gdb、抓包思路上场遇到问题定位手段通常有三层。第一层是日志。我在脚本里已经把每个 agent 的输出重定向到独立日志文件。启动后先打开这些日志看很多问题会直接暴露比如连接失败原因、某个参数不合法、甚至球员在哪个决策阶段发生了异常。这一点非常省时间。第二层是 gdb。如果程序启动后直接段错误Segmentation fault可以用调试版本重新编译然后运行gdb ./bin/agent2d run -t myteam -h 127.0.0.1 -p 6000 -n 1segfault 发生时gdb 会停在崩溃现场输入bt查看调用栈就能快速定位到哪一行代码出了问题。第一次看到bt输出的一堆函数调用可能有点懵但找最靠上的自己项目里的函数基本就是崩溃发生的源头。第三层是网络层面的观察。如果确认程序没崩、但服务器就是没收到注册请求可以看 agent 的日志也可以用 tcpdump 或 wireshark 抓包观察 6000 端口上的数据包交互。不过 99% 的新手问题不需要走到抓包这一步大多是参数、端口、编号这些基础配置问题。写在最后按照这条链路完整跑通一次之后你就算是真正踏进了 RoboCup 仿真2D 的大门。我自己在刚开始时也经历过编译失败、连不上服务器、打开 monitor 一片空白的阶段后来发现这些问题很少来自高深的逻辑反而都败在“先编哪个库”“参数怎么填”“端口对没对上”这类基础细节上。个人经验是把编译和上场这套流程固定成自己的标准操作每次换新代码、换新机器都能十几分钟搞定后面才有时间去研究队形、策略和行为决策。编译这块还有一个小习惯值得养成每次修改了关键代码后尽量先make clean再重新编译不要为了省时间跳过很多“代码明明改了但行为没变”的诡异问题根源就是增量编译留下了旧产物。现在先把这 11 个球员跑起来下一步就可以开开心心地调战术了。
返回列表