为不同的 beaglebone 披风编译机器人控制库 有用的提示:我实际运行的是哪个版本?电机披风无法启动未回答的问题有用的提示:观看串口终端!

问题描述

我应该如何修改和/或编译 Robot Control Library 以与使用略有不同引脚分配的不同 beaglebone cape 一起使用?

我想要重新使用机器人控制库的主要原因是能够通过 PRU 读取第四个编码器。除此之外,我只需要访问编码器和 pwm 模块。

解决方法

TL;DR

修改 PRU 固件以从不同的引脚读取编码器信号很容易。弄清楚如何为我需要的功能组合组装一个工作设备树要困难得多。

我欢迎任何关于我应该如何做到这一点的反馈,或者我可以如何改进我目前拥有的。

机器人控制库+电机罩

Robotics Cape 和 BeagleBone Blue 为伺服控制四个电机提供了交钥匙解决方案, 如果您对以 8V 驱动它们感到满意(例如 2S LIPO 电池)。 Motor Cape 可以处理 更高的驱动电压(和更大的电流),但不包括编码器。将编码器插入 P8 和 P9 Motor Cape 上的标头非常简单,但 BeagleBone 本身只有 3 个编码器计数器 (eQEP)。
机器人控制库通过使用 PRU0 读取第四个编码器解决了这个问题。然而,一些 Motor Cape 与 Robot Control Library 对 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:

最简单的部分 -- 修改 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,EXOR    ; place to store the XOR of old with new AB vals
    .asg    07,B

注意 PRU 固件必须通过运行 makesudo make install 单独编译 在 pru_firmware 目录中。它作为构建其余部分的一部分自动编译 来自顶级 Makefile 的库。

有用的提示:我实际运行的是哪个版本?

有关于修改 librobotcontrol 的报告版本的说明 library/version_updating_howto.txt。我按照这些说明创建了自己的 “私人”版本号,以便我可以确认我实际上正在运行我修改过的 库的版本。此版本由 rc_test_drivers 报告。

然而……如上所述,PRU 固件没有被顶级 Makefile 编译, 所以有一段时间我在 PRU 中运行带有“旧”固件的“新”版本 librobotcontrol

几乎可以工作的部分——设备树

我在文档和代码中找到了 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,MODE6 */
            0x1ac 0x36  /* P9_25,PRU0_r31_7,MODE6 */

编译安装修改后的设备树(makesudo make install BeagleBoard-DeviceTrees repo),我修改了 /boot/uEnv.txt 以调用我的新自定义设备树

uname_r=4.19.94-ti-r42
dtb=am335x-boneblack-custom.dtb
cmdline=coherent_pool=1M

我能够在没有安装披风的情况下启动 BeagleBone,将编码器直接插入所需的引脚 P8_和 P9(包括 P9_25 上的 enc4a)并使用 sudo rc_test_encoders 读取所有四个编码器。 我以为我赢了然后去睡觉了...

电机披风无法启动

一夜好眠后,我将 Motor Cape 连接到 BeagleBone 上,希望不会发生任何变化 我只是通过 P8 和 P9 头直接传递编码器信号。我以为下一步是 对一些 pwm 方向引脚进行类似的调整。

但是,BeagleBone 拒绝在安装了 MotorCape 的情况下启动我的自定义设备树。我回到 “标准”am335x-boneblack-roboticscape.dtb 设备树,并观察到它不会启动 马达角安装。我也开始怀疑 Robotics Cape 的“工厂”安装可能有 毕竟一直在使用叠加层

我从一开始就纠结于是否应该从 Robotics Cape 设备树开始并删除 为了消除资源冲突,我不需要的东西,而不是从“裸”的 BeagleBone 设备树开始 并添加我确实需要的东西。无论准确与否,在我看来,那种映射到试图指定 完整的设备树与提供覆盖层以应用于基本设备树的顶部。后者好像 概念上更正确的路径,所以一旦 Motor Cape 无法使用机器人技术派生的设备树启动, 我决定硬着头皮尝试找出设备树覆盖。

未回答的问题

  • [ ] 为什么安装了电机罩的 BB 不能从 am335x-boneblack-roboticscape.dtb 启动?实际错误是什么?
  • [ ] librobotcontrol 的“正常”安装是安装上面简化的 uEnv.txt 还是使用覆盖层?有用吗?

我还没有可以安装在安装好的斗篷下的 USB-to-TTL 串行电缆,所以我对它知之甚少 为什么或如何无法启动。

最终起作用的部分——设备树覆盖

我最终发现设备树覆盖的集合在 https://github.com/beagleboard/bb.org-overlaysv4.19.x-ti-overlays 分支位于 https://github.com/beagleboard/BeagleBoard-DeviceTrees。我怀疑这可能是一个 正在进行迁移,但有更多与 bb.org-overlays 相关的文档 存储库,所以这就是我选择使用的。

我希望早些找到的一些文档链接:

我创建了 bb.org-overlays 存储库的分叉、克隆和分支,并在以下位置创建了一个新的叠加层 src/arm/CustomCape-00A0.dts 通过将 BBORG_MOTOR-00A2.dtsRoboticsCape-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,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,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,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 端口从安装的斗篷下引出。

https://elinux.org/Beagleboard:BeagleBone_Black_Serial