为不同的 beaglebone cape 编译机器人控制库

Compile the Robot Control Library for a different beaglebone cape

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

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

TL;DR

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

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

机器人控制库+电机斗篷

Robotics Cape 和 BeagleBone Blue 为伺服控制四个电机提供交钥匙解决方案, 如果您对以 8V 驱动它们感到满意(例如 2S LIPO 电池)。机动斗篷可以处理 更高的驱动电压(和更大的电流),但不包括编码器。将编码器插入 P8 和 P9 headerMotor Cape 上的 s 很简单,但 BeagleBone 本身只有 3 个编码器计数器 (eQEP)。
机器人控制库通过使用 PRU0 读取第四个编码器解决了这个问题。然而,一些 Motor Cape 与机器人控制库在 Robotics Cape 上的引脚冲突。

那么,使用机器人控制库来读取编码器和驱动电机有多难呢? Motor Cape 上的引出线不同?如果您已经能够使用 BeagleBone,那么可能一点也不难 设备树覆盖,我不是...

一切从计划开始——引脚选择

Pin PRU Bit Robotics Cape Motor Cape
P8_15 15 Enc 4B --
P8_16 14 Enc 4A M2 Dir
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,         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

N.B. PRU 固件必须由 运行 makesudo make install 单独编译 在 pru_firmware 目录中。它是 not 作为构建其余部分的一部分自动编译的 来自 top-level Makefile 的库。

有用的提示:我实际上是什么版本 运行?

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

报告

但是...如上所述,top-level Makefile 未编译 PRU 固件, 所以有一段时间我是 运行 我的 librobotcontrol 的“新”版本,在 PRU 中有“旧”固件。

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

我在文档和代码中找到了 librobotcontrol 设备树覆盖的参考资料 不再需要,因为机器人斗篷使用了自己的设备树。

The overlay is deprecated now, instead the cape gets its own complete device tree.

我还观察到 运行 推荐的 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 */

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

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

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

机动斗篷无法启动

睡了一夜好觉后,我将 Motor Cape 插到 BeagleBone 上,希望自那以后不会发生任何变化 我只是直接通过 P8 和 P9 headers 传递编码器信号。我以为下一步是 做类似的tw需要一些 pwm 方向引脚。

但是,BeagleBone 拒绝启动我安装了 MotorCape 的自定义设备树。我回到 “标准” am335x-boneblack-roboticscape.dtb 设备树并观察到它无法启动 Motor Cape 已安装。我也开始怀疑机器人斗篷的“工厂”安装可能有 毕竟一直在使用叠加层

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

未回答的问题

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

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

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

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

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

我创建了 bb.org-overlays 存储库的分叉、克隆和分支,并在 src/arm/CustomCape-00A0.dtsBBORG_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,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-based 编码器计数器正常工作,但这似乎 做这个把戏。

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

实用提示:注意串口终端!

我很尴尬,我什至试图在没有串行终端的情况下调试设备树引导问题 打开 beaglebone 以便我可以观察启动顺序。在大约 5 分钟的环氧树脂的帮助下,我 最终能够形成 90 度 header 以将 JTAG 端口从已安装的 cape 下引出。

https://elinux.org/Beagleboard:BeagleBone_Black_Serial