beagleboneblack - 为不同的 beaglebone cape 编译机器人控制库
问题描述
我应该如何修改和/或编译机器人控制库以与使用略有不同引脚分配的不同 beaglebone cape 一起使用?
我想要重用机器人控制库的主要原因是能够通过 PRU 读取第四个编码器。除此之外,我只需要访问编码器和 pwm 模块。
解决方案
TL;博士
修改 PRU 固件以从不同的引脚读取编码器信号很容易。弄清楚如何为我需要的功能组合组装一个工作设备树要困难得多。
我欢迎任何关于我应该如何做到这一点的反馈,或者我可以如何改进我目前所拥有的。
机器人控制库+电机斗篷
Robotics Cape 和 BeagleBone Blue 为伺服控制四个电机提供交钥匙解决方案,如果您对以 8V 驱动它们感到满意(例如 2S LIPO 电池)。Motor Cape 可以处理更高的驱动电压(和更大的电流),但不包括编码器。将编码器插入 Motor Cape 上的 P8 和 P9 接头非常简单,但 BeagleBone 本身只有 3 个编码器计数器 (eQEP)。
机器人控制库通过读取带有 PRU0 的第四个编码器解决了这个问题。但是,Motor Cape 与机器人控制库对 Robotics Cape 的期望之间的一些引脚冲突。
那么,使用机器人控制库读取编码器并驱动电机角上引脚排列略有不同的电机有多难?如果您已经能够胜任 BeagleBone 设备树覆盖,可能根本不难,我不是...
一切从计划开始——引脚选择
别针 | PRU 位 | 机器人斗篷 | 电机斗篷 |
---|---|---|---|
P8_15 | 15 | 编码 4B | -- |
P8_16 | 14 | 编码 4A | M2目录 |
P9_25 | 7 | IMU | -- |
机器人控制库希望第四个编码器出现在 P8_15 和 P8_16 上,但 Motor Cape 将 P8_16 连接为方向信号。只有 12 个引脚被配置为 PRU0 的输入,我最终选择了 P9_25,因为我不需要 IMU 功能。
我发现哪些引脚可用于什么目的的最佳参考是这些 pdf:
- https://ofitselfso.com/BeagleNotes/BeagleboneBlackP8HeaderPinMuxModes.pdf
- https://ofitselfso.com/BeagleNotes/BeagleboneBlackP9HeaderPinMuxModes.pdf
最简单的部分——修改 PRU 代码
机器人控制库将编码器信号输入位定义pru_firmware/src/pur0-encoder.asm
为
; Encoder counting definitions
; these pin definitions are specific to SD-101D Robotics Cape
.asg r0, OLD ; keep last known values of chA and B in memory
.asg r1, EXOR ; place to store the XOR of old with new AB vals
.asg 14, A
.asg 15, B
这可以修改为在第 7 位(寄存器 31,用于所有输入)上查找 A 通道
; Encoder counting definitions
; these pin definitions are specific to SD-101D Robotics Cape
.asg r0, OLD ; keep last known values of chA and B in memory
.asg r1, EXOR ; place to store the XOR of old with new AB vals
.asg 07, A
.asg 15, B
注意PRU 固件必须通过运行make
和sudo make install
在pru_firmware
目录中单独编译。作为从顶级 Makefile 构建库其余部分的一部分,它不会自动编译。
有用的提示:我实际运行的是什么版本?
有关于修改 in 报告版本的librobotcontrol
说明
library/version_updating_howto.txt
。我按照这些说明创建了我自己的“私有”版本号,以便我可以确认我实际上正在运行我修改后的 libray 版本。此版本由rc_test_drivers
.
但是……如上所述,PRU 固件没有被顶级 Makefile 编译,所以有一段时间我librobotcontrol
在 PRU 中运行我的“新”版本和“旧”固件。
几乎成功的部分——设备树
librobotcontrol
我发现不再需要该设备树覆盖的文档和代码中的引用,因为 Robotics Cape 使用了自己的设备树。
现在不推荐使用叠加层,取而代之的是披风拥有自己的完整设备树。
我还观察到运行推荐configure_robotics_dt.sh
替换/boot/uEnv.txt
为以下加载单个设备树二进制文件 (.dtb) 的简化版本
uname_r=4.19.94-ti-r42
dtb=am335x-boneblack-roboticscape.dtb
cmdline=coherent_pool=1M
我最喜欢的关于设备树、pinmux 等的一般信息的参考是 http://www.ofitselfso.com/BeagleNotes/AboutTheDeviceTree.pdf 但是,我现在意识到有些细节有点过时了,所以要小心。
因为我不知道从哪里开始,所以我着手修改机器人斗篷设备树,刚好足以消除与电机斗篷的冲突。我分叉并克隆 了https://github.com/beagleboard/BeagleBoard-DeviceTrees并创建了两个新文件
am335x-boneblack-custom.dts
- 备份
am335x-boneblack-roboticscape.dts
- 更改
model
为使新设备树可识别 - 改为
#include
指向am335x-custom.dtsi
而不是am335x-roboticscape.dtsi
- 备份
am335x-custom.dtsi
- 备份
am335x-roboticscape.dtsi
- 删除了一大堆我认为我不再需要的东西
- 将 P9_25(而不是 P8_16)路由到 PRU0
- 备份
前
/* PRU encoder input */
0x03c 0x36 /* P8_15,PRU0_r31_15,MODE6 */
0x038 0x36 /* P8_16,PRU0_r31_14,MODE6 */
后
/* PRU encoder input */
0x03c 0x36 /* P8_15,PRU0_r31_15,MODE6 */
0x1ac 0x36 /* P9_25,PRU0_r31_7,MODE6 */
编译并安装修改后的设备树(make
,sudo make install
在
BeagleBoard-DeviceTrees
repo 中)后,我修改/boot/uEnv.txt
为调用我的新自定义设备树
uname_r=4.19.94-ti-r42
dtb=am335x-boneblack-custom.dtb
cmdline=coherent_pool=1M
我能够在没有安装 cape 的情况下启动 BeagleBone,将编码器直接插入 P8_和 P9 上所需的引脚(包括 P9_25 上的 enc4a)并使用sudo rc_test_encoders
. 我以为我赢了,就去睡觉了……
电机斗篷无法启动
睡了一夜好觉后,我将 Motor Cape 插到 BeagleBone 上,因为我只是将编码器信号直接通过 P8 和 P9 接头传递,因此没有任何改变。我认为下一步将对一些 pwm 方向引脚进行类似的调整。
但是,BeagleBone 拒绝在安装了 MotorCape 的情况下启动我的自定义设备树。我回到“标准”am335x-boneblack-roboticscape.dtb
设备树并观察到安装了 Motor Cape 时它也无法启动。我也开始怀疑机器人斗篷的“工厂”安装可能一直在使用覆盖层
我从一开始就纠结于是否应该从 Robotics Cape 设备树开始并删除我不需要的东西以消除资源冲突,而不是从“裸”BeagleBone 设备树开始并添加我所做的事情需要。无论准确与否,在我看来,这种映射是尝试指定完整的设备树,而不是提供覆盖以应用于基础设备树之上。后者在概念上似乎是更正确的路径,因此一旦 Motor Cape 无法使用源自 robots-cape 的设备树启动,我决定硬着头皮尝试找出设备树覆盖。
未回答的问题
- [ ] 为什么
am335x-boneblack-roboticscape.dtb
安装了电机罩后 BB 无法启动?实际错误是什么? librobotcontrol
[ ]安装上述简化版的“正常”安装uEnv.txt
还是使用覆盖?它有效吗?
我还没有可以安装在已安装斗篷下的 USB 转 TTL 串行电缆,所以我对为什么或如何无法启动知之甚少。
最终起作用的部分——设备树覆盖
我最终发现设备树覆盖的集合在
https://github.com/beagleboard/bb.org-overlays和 https://github.com/beagleboard/BeagleBoard-DeviceTrees 的分支v4.19.x-ti-overlays
中都可以
使用。我怀疑这可能是一个正在进行的迁移,但是有更多与
存储库相关的文档,所以这是我选择使用的。bb.org-overlays
我希望我早先找到的一些文档链接:
- https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#U-Boot_Overlays
- https://github.com/cdsteinkuehler/beaglebone-universal-io
- https://vadl.github.io/beagleboneblack/2016/07/29/setting-up-bbb-gpio
我创建了分叉、克隆和分支bb.org-overlays
repo,并
src/arm/CustomCape-00A0.dts
通过将来自BBORG_MOTOR-00A2.dts
和RoboticsCape-00A0.dts
/*
* Device Tree Overlay for custom cape trying to reuse Robot Control Library's
* reading of 4x optical encoders.
*/
/*
pinmux control byte map courtesy of http://beaglebone.cameon.net/
Bit 5: 1 - Input, 0 - Output
Bit 4: 1 - Pull up, 0 - Pull down
Bit 3: 1 - Pull disabled, 0 - Pull enabled
Bit 2 \
Bit 1 |- Mode
Bit 0 /
*/
/dts-v1/;
/plugin/;
/ {
compatible = "ti,beaglebone-black";
/* identification */
part-number = "CustomCape";
/* version */
version = "00A0";
exclusive-use =
"P8.11", /*QEP_2B*/
"P8.12", /*QEP_2A*/
"P8.16", /*PRU_ENCODER_A*/
"P8.33", /*QEP_1B*/
"P8.35", /*QEP_1A*/
"P9.27", /*QEP_0B*/
"P9.41", /*MOT_STBY*/
"P9.42"; /*QEP_0A*/
/*
* Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/
*/
fragment@0 {
target-path="/";
__overlay__ {
chosen {
overlays {
CustomCape-00A0 = __TIMESTAMP__;
};
};
};
};
fragment@1 {
target = <&am33xx_pinmux>;
__overlay__ {
/****************************************
* pinmux helper
****************************************/
mux_helper_pins: pins {
pinctrl-single,pins = <
/* EQEP */
0x1A0 0x31 /* P9_42,EQEP0A, MODE1 */
0x1A4 0x31 /* P9_27,EQEP0B, MODE1 */
0x0D4 0x32 /* P8_33,EQEP1B, MODE2 */
0x0D0 0x32 /* P8_35,EQEP1A, MODE2 */
0x030 0x34 /* P8_12,EQEP2A_in, MODE4 */
0x034 0x34 /* P8_11,EQEP2B_in, MODE4 */
/* PRU encoder input */
0x03c 0x36 /* P8_15,PRU0_r31_15,MODE6 */
0x1ac 0x36 /* P9_25,PRU0_r31_7,MODE6 */
>;
};
};
};
/****************************************
Pinmux Helper
activates the pinmux helper list of pin modes
****************************************/
fragment@2 {
target = <&ocp>;
__overlay__ {
test_helper: helper {
compatible = "bone-pinmux-helper";
pinctrl-names = "default";
pinctrl-0 = <&mux_helper_pins>;
status = "okay";
};
};
};
/*
* Free up the pins used by the cape from the pinmux helpers.
*/
fragment@3 {
target = <&ocp>;
__overlay__ {
P8_11_pinmux { status = "disabled"; }; /* enc3b */
P8_12_pinmux { status = "disabled"; }; /* enc3a */
P8_15_pinmux { status = "disabled"; }; /* enc4b */
P8_33_pinmux { status = "disabled"; }; /* enc0 */
P8_35_pinmux { status = "disabled"; }; /* enc0 */
P9_25_pinmux { status = "disabled"; }; /* enc4a */
P9_27_pinmux { status = "disabled"; }; /* enc1b */
P9_92_pinmux { status = "disabled"; }; /* enc1a */
};
};
/****************************************
Encoders
****************************************/
fragment@9 {
target = <&eqep0>;
__overlay__ {
count_mode = <0>; /* 0 - Quadrature mode, normal 90 phase offset cha & chb. 1 - Direction mode. cha input = clock, chb input = direction */
swap_inputs = <0>; /* Are channel A and channel B swapped? (0 - no, 1 - yes) */
invert_qa = <1>; /* Should we invert the channel A input? */
invert_qb = <1>; /* Should we invert the channel B input? I invert these because my encoder outputs drive transistors that pull down the pins */
invert_qi = <0>; /* Should we invert the index input? */
invert_qs = <0>; /* Should we invert the strobe input? */
status = "okay";
};
};
fragment@10 {
target = <&eqep1>;
__overlay__ {
count_mode = <0>; /* 0 - Quadrature mode, normal 90 phase offset cha & chb. 1 - Direction mode. cha input = clock, chb input = direction */
swap_inputs = <0>; /* Are channel A and channel B swapped? (0 - no, 1 - yes) */
invert_qa = <1>; /* Should we invert the channel A input? */
invert_qb = <1>; /* Should we invert the channel B input? I invert these because my encoder outputs drive transistors that pull down the pins */
invert_qi = <0>; /* Should we invert the index input? */
invert_qs = <0>; /* Should we invert the strobe input? */
status = "okay";
};
};
fragment@11 {
target = <&eqep2>;
__overlay__ {
count_mode = <0>; /* 0 - Quadrature mode, normal 90 phase offset cha & chb. 1 - Direction mode. cha input = clock, chb input = direction */
swap_inputs = <0>; /* Are channel A and channel B swapped? (0 - no, 1 - yes) */
invert_qa = <1>; /* Should we invert the channel A input? */
invert_qb = <1>; /* Should we invert the channel B input? I invert these because my encoder outputs drive transistors that pull down the pins */
invert_qi = <0>; /* Should we invert the index input? */
invert_qs = <0>; /* Should we invert the strobe input? */
status = "okay";
};
};
/****************************************
PRU
****************************************/
fragment@31 {
target = <&pruss>;
__overlay__ {
status = "okay";
};
};
};
我将自定义叠加层添加到/boot/uEnv.txt
并禁用了视频和音频叠加层
uname_r=4.19.94-ti-r42
#uuid=
#dtb=
###U-Boot Overlays###
###Documentation: http://elinux.org/Beagleboard:BeagleBoneBlack_Debian#U-Boot_Overlays
###Master Enable
enable_uboot_overlays=1
###
###Additional custom capes
uboot_overlay_addr4=/lib/firmware/CustomCape-00A0.dtbo
###
###Custom Cape
#dtb_overlay=/lib/firmware/<file8>.dtbo
###
###Disable auto loading of virtual capes (emmc/video/wireless/adc)
#disable_uboot_overlay_emmc=1
disable_uboot_overlay_video=1
disable_uboot_overlay_audio=1
#disable_uboot_overlay_wireless=1
#disable_uboot_overlay_adc=1
###
###PRUSS OPTIONS
###pru_rproc (4.19.x-ti kernel)
uboot_overlay_pru=/lib/firmware/AM335X-PRU-RPROC-4-19-TI-00A0.dtbo
###
###Cape Universal Enable
enable_uboot_cape_universal=1
###
###U-Boot Overlays###
cmdline=coherent_pool=1M net.ifnames=0 lpj=1990656 rng_core.default_quality=100 quiet
我没有声明最优性甚至正确性,但是无论是否安装了 Motor Cape,此配置都可以启动,并且我可以使用rc_test_encoders
. 安装 Motor Cape 后,uBoot 会正确拾取并应用BBORG_MOTOR-00A2
覆盖层。老实说,我认为我需要对 PRU 进行更多配置才能使机器人控制库中基于 PRU 的编码器计数器正常工作,但这似乎可以解决问题。
我欢迎任何关于我应该如何做到这一点的反馈,或者我可以如何改进我目前所拥有的。
有用的提示:观看串行终端!
让我感到尴尬的是,我什至尝试调试设备树启动问题,而没有先打开 Beaglebone 的串行终端,这样我就可以观察启动顺序。在 5 分钟环氧树脂的帮助下,我最终能够制作一个 90 度的接头,将 JTAG 端口从已安装的斗篷下取出。
推荐阅读
- c# - 如何在 C# WPF 中从 ListView/XML 中完全删除一个项目?
- python - Numpy 数组未更新
- java - Spring Request 处理失败;嵌套异常是 java.lang.NoSuchMethodException:
- python - Pycron 不仅在控制台启动时运行
- react-native - Expo + vagrant,metro 捆绑包不起作用
- javascript - 试图在函数外传递变量
- python - ','运算符在python中代表什么?
- django - 如何使用通配符作为键/对象在 django 中生成 aws 预签名 url
- sql - 我应该将实际数据和预测数据分成 2 个表吗?
- tcp - Erlang TCP 服务器总是在接受时关闭