ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Ubuntu 22.04源码编译GNU Radio/UHD/gr-ieee802-11指南

Ubuntu 22.04源码编译GNU Radio/UHD/gr-ieee802-11指南 省流版先说结论这套环境我前后配了两次第一次纯靠apt装二进制包省心但gr-ieee802-11死活跑不起来第二次老老实实从源码编UHD、VOLK、GNU Radio再把WiFi收发模块gr-ieee802-11接上虽然中间踩了五六个坑但最后USRP能收能发802.11抓包和注入都通了。这篇文章就是第二次编译全过程的还原偏记录向但每一步的命令、CMake参数、报错解法都写清楚了适合想在自己Ubuntu 22.04上折腾SDR开发环境的哥们参考。1. 内容整体设计与思路拆解先把这次要编译的几个东西串一遍。GNU Radio是一个开源软件无线电生态核心是基于Python和C的流图开发框架能让你用积木式模块搭建信号处理流程。UHDUSRP Hardware Driver是Ettus公司USRP系列硬件的驱动库负责上位机和射频前端之间的通信。VOLKVector-Optimized Library of Kernels则是一个底层SIMD优化库GNU Radio的很多信号处理模块在运行时都会调度VOLK里的高性能内核相当于给计算密集型模块加速用的。而gr-ieee802-11这个模块是GitHub上开源的IEEE 802.11b/g/n收发信机实现简单说就是让USRP能发射和接收WiFi信号。它依赖新版GNU Radio和UHD但问题在于它一直在跟着GNU Radio主线走如果你系统里装的是Ubuntu源里自带的GNU Radio 3.10.1.1那大概率会遇到API接口不匹配的问题比如gnuradio::pmx消息接口变了、boost::shared_ptr换成了std::shared_ptr等。所以这次我的整体编译路线是UHD 4.5.0 → VOLK 3.1.0 → GNU Radio 3.10.5.1 → gr-ieee802-11最新master分支。为什么要这个顺序因为VOLK虽然是独立项目但GNU Radio编译时会去检测它UHD也会被GNU Radio的gr-uhd模块依赖而gr-ieee802-11又同时依赖GNU Radio的runtime和UHD的device API所以必须自底向上先把基础层编干净。有人可能会问GNU Radio和UHD直接apt install不就行了吗我明确说如果你只跑GNU Radio自带的那些模块比如信号源、滤波器、FFT、星座图那apt包完全够用而且省时间。但gr-ieee802-11是个比较挑环境的模块——它用到了一些较新的meson构建逻辑、C17标准、以及UHD 4.x新版APIUbuntu 22.04源里的GNU Radio和UHD版本偏旧我实测直接编译gr-ieee802-11会报UHD version not found之类的问题。所以从源码编译是绕不开的路。1.1 为什么选这几个版本而不是最新版版本选择上我没有盲目追新。UHD目前官方稳定版已经到了4.6甚至4.8但gr-ieee802-11的CMakeLists.txt里对UHD版本有范围要求某些新版本里移除了旧API反而会编不过。我最终选了4.5.0这个版本在USRP X310和B210上表现都很稳而且和GNU Radio 3.10.5.1配合良好。同理GNU Radio我没有选3.11或者main分支因为gr-ieee802-11虽然紧跟主线但难免有几天跟不上的情况与其赌它适配最新版不如选一个生态里验证比较多的3.10系列。VOLK选3.1.0也是因为它是GNU Radio 3.10.5.1发布时配套测试过的版本没必要为了“更新”而更新。1.2 一次编译涉及的核心模块关系我自己画了个依赖图在脑子里VOLK在最底层它只依赖libboost和libcpu相关特性检测主要提供各种SIMD内核。UHD在中间层它不依赖GNU Radio但依赖Boost、libusb、Python3等。GNU Radio最上面它同时依赖VOLK和UHD如果要gr-uhd模块的话。gr-ieee802-11又在GNU Radio之上依赖GNU Radio的runtime、qtgui、network等模块并在运行时通过UHD的API控制USRP。这个依赖关系决定了编译顺序和排错方向后面遇到链接错误的时候基本就能定位是哪一层出了问题。2. 核心细节解析与实操要点2.1 安装基础依赖包这一步很多人会忽略直接跳过去源码编译然后卡在各种各样的头文件缺失上。实际上Ubuntu 22.04下先花10分钟把依赖包装齐后面能省一小时查错的时间。我在干净系统上执行的是sudo apt update sudo apt install -y \ build-essential cmake git pkg-config \ libboost-all-dev libgmp-dev libmpfr-dev \ libfftw3-dev libgsl-dev libsdl1.2-dev \ libqt5opengl5-dev qtbase5-dev libqwt-qt5-dev \ liblog4cpp5-dev libgtest-dev libxml2-dev \ python3-dev python3-pip python3-numpy python3-mako \ python3-six python3-lxml python3-setuptools \ swig doxygen graphviz \ libusb-1.0-0-dev libusb-dev \ libcomedi-dev libcppunit-dev \ libsndfile1-dev libasound2-dev \ libblas-dev liblapack-dev \ libcurl4-openssl-dev libudev-dev \ python3-pyqt5 python3-qwt \ portaudio19-dev pavucontrol \ python3-scipy python3-matplotlib \ libi2c-dev libspdlog-dev这里面有几个值得解释一下。libvolk-dev和libvolk2-dev这两个我故意没装因为后面要自己编译VOLK装系统版会导致头文件冲突这是血的教训。libboost-all-dev是必须的UHD和GNU Radio都会用Boost的shared_ptr、thread、program_options等库不装全后面会有一堆链接错误。libqwt-qt5-dev和qtbase5-dev是用来编译GNU Radio的Qt GUI模块的如果你想看星座图、频谱图这几个包缺一不可。Python方面我用了系统默认的Python 3.10。这里有个点要注意不要手贱装conda或者pyenv把自己系统的Python替换掉GNU Radio 3.10的gr-modtool和gnuradio-companion对系统Python路径和site-packages路径有硬编码一旦Python路径变了各种import不了模块的问题会接踵而至。2.2 为什么不建议用pip安装GNU Radio网上有些教程会让你直接用pip install gnuradio或者用conda install -c conda-forge gnuradio这两个方案在实际做SDR开发时都不太推荐。conda版本的好处是简单但问题在于conda会创建一套隔离的Python环境你后面自己编译的gr-ieee802-11模块如果绑定的是系统Python那就要想办法把模块装进conda的site-packages里非常折腾而且一旦conda更新了包版本又对不上了。pip装GNU Radio更是坑因为它本质上就是调conda-forge的库pip会把一堆二进制包拉进来看起来能用但和usb设备配合时UHD的固件刷写路径、pybind11生成的Python绑定路径全混乱最后你会发现自己连USRP的固件都刷不进去。所以自己编译虽然费时间但路径清晰模块可控后续加新模块也方便。3. 实操过程与核心环节实现3.1 编译UHD 4.5.0UHD是整个链路的基石如果它不稳后面的东西全白搭。我先从GitHub拉取代码然后签出4.5.0标签git clone --recursive https://github.com/EttusResearch/uhd.git cd uhd git checkout v4.5.0编译之前有个重要的准备步骤把UHD的Python绑定打开。UHD的Python API对于gr-ieee802-11不是硬依赖但开发调试时会用到uhd.usrp.MultiUSRP来写简单的收发脚本所以我还是把ENABLE_PYTHON_API设置为ON。具体编译命令mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX/usr/local \ -DENABLE_PYTHON_APION \ -DPYTHON_EXECUTABLE$(which python3) \ -DENABLE_STATIC_LIBSOFF \ -DCMAKE_BUILD_TYPERelease \ .. make -j$(nproc) sudo make install sudo ldconfig这里要说明一下为什么CMAKE_INSTALL_PREFIX用/usr/local而不是默认的/usr。如果用/usr/local后续GNU Radio在编译时检测UHD头文件会去/usr/local/include里找而Ubuntu的apt包如果也装了UHD两个路径会打架。我的经验是要么就完全不用apt装UHD要么统一默认路径。为了省心我卸载了所有libuhd相关的包然后直接用/usr/local。编译完成后建议运行一下uhd_find_devices如果提示No UHD Devices Found别慌这是正常的因为还没插USRP。但至少说明库文件安装没问题Python绑定也能正常加载。对于开发者来说还有一个值得检查的点是UHD的固件路径。默认情况下UHD会从/usr/local/share/uhd/images下寻找fpga固件。刷固件的时候用uhd_image_loader命令。3.2 编译VOLKVOLK编译其实是最顺的它本身不带太多外部依赖只要Boost和Python环境干净就行。git clone --recursive https://github.com/gnuradio/volk.git cd volk git checkout v3.1.0 mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX/usr/local \ -DCMAKE_BUILD_TYPERelease \ -DPYTHON_EXECUTABLE$(which python3) \ .. make -j$(nproc) sudo make install sudo ldconfig这里我用了一个技巧编译之前先跑一下volk_profile工具。它会在当前用户目录下生成.volk_profile文件记录当前CPU上各个VOLK内核的实测性能数据。这样后面GNU Radio运行时能更精准地选最快的SIMD实现尤其在WiFi这种高吞吐场景下性能差别是能感知到的。VOLK编译完之后可以做个快速验证python3 -c import volk; print(volk.get_power_of_volk())能正确输出版本和CPU特性就说明没问题。3.3 编译GNU Radio 3.10.5.1GNU Radio编译是整个过程中最花时间的一步单机8核编译大概要30-40分钟。它的大头在于grcGNU Radio Companion、gr-qtgui、gr-uhd这几个模块的编译尤其是Python绑定那一层。源码获取git clone --recursive https://github.com/gnuradio/gnuradio.git cd gnuradio git checkout v3.10.5.1然后建立build目录编译mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX/usr/local \ -DCMAKE_BUILD_TYPERelease \ -DPYTHON_EXECUTABLE$(which python3) \ -DENABLE_DEFAULTON \ -DENABLE_GR_UHDON \ -DENABLE_GR_QTGUION \ -DENABLE_GR_NETWORKON \ -DENABLE_GRCON \ -DENABLE_PYTHONON \ -DENABLE_DOXYGENOFF \ -DENABLE_TESTINGOFF \ .. make -j$(nproc) sudo make install sudo ldconfig注意这里有个关键点ENABLE_GR_NETWORK要设为ON。gr-ieee802-11的某些示例用到了UDP收发模块如果network模块没编译后面跑示例的时候会提示找不到gr::network::udp_sink。我第一次编译时就是没开这个选项导致后续示例脚本老报错排查了半天。另外一个容易被忽略的是swig和pybind11的关系。GNU Radio 3.10从默认绑定方式从SWIG切换到了pybind11但某些模块如gr-qtgui仍然依赖pybind11生成Python绑定。所以编译前确认系统里有pybind11-dev并且版本最好是2.10以上这个在apt里一般都有。编译完成后验证gnuradio-config-info --version python3 -c import gnuradio; print(gnuradio.version)如果能正常显示3.10.5.1那说明主体OK。再启动一下gnuradio-companion看看能不能正常打开图形界面。3.4 编译gr-ieee802-11模块这是本次编译的重头戏。gr-ieee802-11是一个外部的out-of-tree模块它不在GNU Radio主仓库里需要单独拉取。git clone https://github.com/gr-ieee802-11/gr-ieee802-11.git cd gr-ieee802-11这个模块没有像GNU Radio那样用CMake默认配置而是用了Meson构建系统。这也是一个坑点很多人拿着cmake的习惯去编译它结果发现没有CMakeLists.txt直接懵了。它的构建文件是meson.build。编译过程meson setup build --prefix/usr/local ninja -C build sudo ninja -C build install sudo ldconfig这里有一个细节Meson构建的时候会自动检测GNU Radio的安装路径。因为我前面把GNU Radio装到了/usr/local所以这里没额外指定pkg-config路径。如果你安装到其他自定义路径就需要设置PKG_CONFIG_PATH环境变量export PKG_CONFIG_PATH/your/prefix/lib/pkgconfig:$PKG_CONFIG_PATH编译完成后模块的Python绑定会装到/usr/local/lib/python3.10/site-packages/这时候你需要在运行Python之前让它能找到gr-ieee802-11的模块。可以把以下变量写进~/.bashrc里省得每次都设置export PYTHONPATH/usr/local/lib/python3.10/site-packages:$PYTHONPATH export LD_LIBRARY_PATH/usr/local/lib:$LD_LIBRARY_PATH验证模块是否导入成功python3 -c import gr_ieee802_11; print(ok)不过这里说句实话gr-ieee802-11的模块名在不同版本有变化有的版本是import gr_ieee802_11有的版本是from gnuradio import ieee802_11。建议编译完先去Python里pkgutil.iter_modules()搜一下找到正确的模块名再导入不然会被ModuleNotFoundError搞得很烦。3.5 WiFi收发功能验证流程编译安装完成后最关心的肯定是能不能真的收WiFi信号。这里我把验证方法也说一下。gr-ieee802-11仓库的examples目录里带了一些示例脚本比如wifi_phy_hier.py和wifi_loopback.py但最典型的是接收脚本一般叫wifi_rx.py。实测如果要抓WiFi Beacon帧可以这样跑python3 examples/wifi_rx.py --freq2.437G --rate20M --argstypeb200参数里freq是中心频率2.437G是WiFi 2.4G频段的6信道rate是采样率20M是WiFi 20MHz带宽的采样率args指定USRP设备类型B200就写typeb200X310就写typex300。如果一切正常脚本起来之后会打开一个Qt GUI窗口里面有星座图、FFT频谱、解调后的比特流输出。把手机开个热点或者拿路由器放旁边只要USRP的接收频率对准了就能在终端看到“Captured frame”之类的打印Qt窗口里也会出现明显的802.11信号特征。我实测下来B210在2.4GHz频段收Beacon是最轻松的因为Beacon是广播帧不需要配对只要信号强度够就能抓到。用X310也试过但X310是外接时钟和网口的配置复杂一些对新手不太友好。发射的话可以用wifi_tx.py同样指定freq、rate、args它会周期性发送特定的WiFi帧。需要注意的是发射时一定要接好天线不然反射功率过大容易烧前端。USRP的前端没有做内置的收发切换保护这一点和真实WiFi网卡不太一样所以用的时候要注意。4. 常见问题与排查技巧实录4.1 编译gr-ieee802-11时提示找不到gnuradio/block_api.h这个报错几乎每个人都遇到过它本质是gr-ieee802-11在找GNU Radio头文件时去的是系统默认路径而我的GNU Radio安装在/usr/local。解决办法很简单确认pkg-config路径export PKG_CONFIG_PATH/usr/local/lib/pkgconfig:/usr/local/lib/python3.10/site-packages/pkgconfig:$PKG_CONFIG_PATH然后再跑meson setup重新生成build配置。4.2 运行示例时提示ModuleNotFoundError: No module named gnuradio.blocks这个问题的根源是GNU Radio的Python绑定没有装到Python搜索路径里。处理方法是检查/usr/local/lib/python3.10/site-packages目录里有没有gnuradio目录。如果有那就是PYTHONPATH没设好如果没有说明编译时ENABLE_PYTHONOFF需要重新编译GNU Radio。4.3 UHD连接B210时报USB 3.0带宽不够这个坑我见过不少。B210虽然是USB 3.0接口但很多廉价USB hub或者劣质数据线只能跑到USB 2.0的速度导致采样率一超过10M就会丢包或者报Bandwidth Insufficient。换根高质量的数据线、直接插主板USB 3.0口蓝色口、关掉省电模式基本能解决。4.4 VOLK编译时报找不到vc_compiler这是VOLK的新版对编译器版本有要求。Ubuntu 22.04自带GCC 11如果不满足会报这个错。解决办法是装个GCC-12或者用clang编译。我实测用clang编译VOLK完全没问题而且性能也很好。5. 调试进阶怎么判断链路是否健康编译安装都通过之后别急着跑WiFi收发先做几个健康检查。第一个检查是UHD时间同步。USRP设备内部有FPGA时钟如果时间源不锁定收发会严重错位表现为接收的星座图旋转跳跃。用以下命令看uhd_usrp_probe看输出的clock locked状态。如果是internal时间源且显示OK说明没问题如果是external参考时钟要确认参考信号接入了。第二个检查是VOLK性能优化。运行volk_profile让它自动测一遍当前平台的最佳内核因为我发现很多编译报错或者性能低下的问题说到底都是VOLK没有针对性优化。跑完之后GNU Radio的FFT、滤波器这些模块会自动选用最合适的内核WiFi接收的性能能明显提升。第三个检查是GRC图能不能正确加载gr-ieee802-11的block。打开GNU Radio Companion在block列表里搜ieee802_11如果能找到wifi_mac、wifi_phy等模块说明模块注册成功Python绑定也正确。不过说实话GRC里虽然能看到这些模块但gr-ieee802-11的完整收发流程更多还是靠运行examples目录里的Python脚本因为WiFi的MAC层状态机比较复杂GRC画流图反而不直观。我自己是先用脚本调通再用GRC做简单验证。6. 性能优化的一些体会WiFi信号处理对计算资源的要求比较高。我用B210接收20MHz带宽的WiFi信号跑grc流图时CPU占用能到70%到80%。如果电脑比较老建议从这三方面优化。第一把GNU Radio的block affinity设置到不同CPU核心上。默认情况下所有block都在一个进程里跑GNU Radio的调度器会把它们分配到同一个核心组需要手动指定affinity。比如在GRC的Options里设置thread affinity或者Python脚本里调用tb.set_affinity()。这个优化对多核机器效果明显。第二块大小samples per symbol调大。WiFi接收机里很多模块的块大小默认是几千个采样如果调整到一万以上可以减少调度次数吞吐量能提升不少。第三USRP接收增益要适中。我发现很多人喜欢把tx_gain和rx_gain调到最大其实增益太高会导致接收机饱和星座图一团糊。802.11信号本身接收灵敏度很高我通常把B210的rx_gain设置到20-25dB就足够了除非信号特别弱再往上加。7. 写在最后的几个避坑心得编译这套环境整体下来不算难但坑确实不少。总结几条实操心得希望能给后来的朋友省点时间。第一严格按顺序编译不要跳步。先VOLK、再UHD、再GNU Radio、最后gr-ieee802-11这个顺序是铁律。颠倒顺序会导致依赖检测失败白白浪费时间。第二版本锁定要早做。GNU Radio 3.10.x和UHD 4.5.x不是随便组合都能出的。如果你想换版本先把依赖矩阵查清楚再动手。第三不要混用包管理器安装的库和自己编译的库。我第二次编译时故意把apt的libuhd、libvolk、gnuradio全部卸载干净才避免了很多奇怪的运行时报错。第四这个环境搞完之后强烈建议写一个安装脚本记录所有步骤。因为过一段时间你可能会在另一台机器上重新配环境到时候照着脚本走能省大量试错时间。我现在这台机器就是直接跑当初的脚本恢复的环境半小时全部搞定。第五如果只是做WiFi抓包分析而不打算深度定制信号处理不如直接用现成的软件方案比如Wireshark加普通WiFi网卡的monitor模式就能完成很多工作。gr-ieee802-11的价值在于你可以完整控制物理层调制方式和MAC帧结构适合做协议研究和原型验证追求的是自由度而不是简单易用。想清楚自己的需求再决定要不要投入时间去编译这一整套环境。
返回列表