里程计

里程计是通过使用一种称为旋转编码器的传感器来测量车辆轮胎的旋转来计算车辆的速度和行驶距离的方法。这个编码器可以安装在电机上、主驱动轴上或者单独的车轮上。使用编码器的优势在于它与油门相连,因此您的车辆可以可靠地控制实际速度,而不仅仅是发出一个电机控制信号,该信号会根据赛道的坡度、表面情况或传动系统中的机械摩擦而产生更快或更慢的速度。简而言之,编码器能够更好地控制车辆的速度。

编码器有不同的形式:

  • 四相编码器使用双传感器测量轴转动时的脉冲,并具有非常精确的优点,能够区分正向和反向旋转。这些编码器可以使用测量磁脉冲的霍尔效应传感器或通过一个完全封闭的有凹槽的光盘通过光传感器来测量光脉冲。
  • 单相编码器使用单个传感器计数脉冲,因此无法确定运动的方向。它们通常比四相编码器更小更便宜。一个常见的例子是光学版本,它使用LED发射器/接收器传感器和一个连接到输出轴的有凹槽的光盘。当输出轴旋转时,光盘也会旋转,因此光线会被中断并计数这些脉冲。这些传感器便宜且易于安装,但无法确定旋转方向。

有几种方法可以在Donkey中读取编码器:

Arduino: 推荐的方法是使用一个运行Donkeycar附带的Arduino示例之一的兼容Arduino微控制器。由于微控制器专门用于计数脉冲,它可以保持准确的计数,即使是非常高分辨率的编码器。这对于使用高分辨率编码器非常关键,以确保不会丢失任何编码器脉冲并导致计数不准确。有两个可用的Arduino示例:

  • mono_encoder.ino 支持单通道编码器,例如带有20个凹槽编码器盘的简单编码器。
  • quadrature_encoder.ino 支持双通道四相编码器,可以检测方向和编码器计数。

这两个示例都支持单个编码器或两个编码器的差动传动配置。它们可以使用中断来编译高分辨率编码器,或者作为轮询编码器进行编译,具有健壮的去抖动功能。这两个示例在Donkeycar请求时通过USB串行端口将计数传输到Raspberry Pi,这减轻了Rpi的处理负载。

GPIO: 如果您使用的是连接到电机输出轴或传动轴的低分辨率单相编码器,那么树莓派的GPIO引脚可能足以计数脉冲。请记住,GPIO引脚仅支持3.3V设备;如果您可以将编码器的VCC供电为3.3V,则通常会输出3.3V的脉冲,这样您可以直接将其连接到树莓派的GPIO引脚。

支持的编码器

以下是支持的旋转编码器示例:

硬件设置

如何安装编码器取决于您使用的编码器类型。例如,这里是一种在主传动轴上安装四相位编码器的方法。这里是一个更复杂的双编码器设置示例。

但这是最简单的方法,使用一个便宜而简单的光学编码器安装在标准Donkeycar底盘的主传动轴上(如果您的底盘不同,相同的总体方法应该适用,尽管您可能需要找到其他地方来安装传感器):

首先,拆卸主传动轴上的盖板。将后轮稍微往后倾斜一点,然后您应该能够拆下轴。

传动轴

现在,扩大您的传感器配套光学编码器盘上的孔(使用钻头或Dremel磨石),以便您可以将其滑到轴上。将一枚橡胶垫圈(您可以使用通常用于安装舵机的垫圈,但任何适合尺寸的垫圈都可以)套在轴上,并将其推入编码器盘孔中。如果您没有橡胶垫圈,可以在轴上缠绕胶带,直到足够大以牢固固定盘。确保它放置在正确的位置后,使用几滴超级胶水或热熔胶固定住它。

传动轴

传动轴

在覆盖传动轴的盖板上切出一个小缺口(此处用铅笔标记),以便您可以在那里安装编码器传感器,并确保盘可以在舵机前方的缺口中自由转动。

盖板

现在重新安装盖板并钻两个孔,以便您可以螺丝固定编码器传感器。沿着轴滑动盘,以确保它不会与传感器发生卡阻。

盖板

使用三根公对母跳线连接编码器传感器到您的树莓派GPIO引脚,连接方式如下。将GND、V+(可能标有5V或3.3V)和数据引脚(可能标有"Out"或"D0")连接到树莓派的5V、Ground和GPIO 13,如下图所示(如果您的传感器编码器有四个引脚,则忽略标有"A0"的引脚): 接线图

注意:如果您已经在使用GPIO 13进行其他用途,例如RC输入或输出,您可以使用任何其他可用的GPIO引脚。只需相应地在myconfig.py文件中更改ODOM_PIN编号即可。

软件设置

myconfig.py 中启用里程计(odometry)。

#
# ODOMETRY
#
HAVE_ODOM = False               # 是否有里程计/编码器
HAVE_ODOM_2 = False             # 是否有第二个里程计/编码器,如差动驱动机器人。
                                # 在这种情况下,'first' 编码器是左轮编码器,
                                # 第二个编码器是右轮编码器。
ENCODER_TYPE = 'GPIO'           # 编码器类型是什么?GPIO|arduino。
                                # - 'GPIO' 指的是将单通道编码器直接连接到 RPi/Jetson 的 GPIO 引脚。
                                #   根据板上编号,将 ODOM_PIN 设置为 GPIO 引脚。
                                # - 'arduino' 通常指通过串口连接的任何微控制器。
                                #   将 ODOM_SERIAL 设置为连接微控制器的串口。
                                #   请参阅 'arduino/encoder/encoder.ino',其中有一个 Arduino 脚本,
                                #   用于实现从微控制器向主机发送读数的连续和按需协议。
ENCODER_PPR = 20                # 编码器轴每转的脉冲数(ticks)。
ENCODER_DEBOUNCE_NS = 0         # 在整合后续编码器脉冲之前等待的纳秒数。
                                # 对于具有噪声转换的编码器,可以使用此参数来排除噪声引起的额外中断。
                                # 如果需要,可以使用示波器、逻辑分析仪或简单地尝试不同的值来确定确切的值。
FORWARD_ONLY = 1
FORWARD_REVERSE = 2
FORWARD_REVERSE_STOP = 3
TACHOMETER_MODE=FORWARD_REVERSE # FORWARD_ONLY、FORWARD_REVERSE 或 FORWARD_REVERSE_STOP
                                # 对于双通道正交编码器,'FORWARD_ONLY' 始终是正确的模式。
                                # 对于单通道编码器,转速计模式取决于应用程序。
                                # - FORWARD_ONLY 始终递增脉冲;实际上假设车辆始终向前移动并始终有正的油门。
                                #   这适用于在开放的赛道上进行比赛,车辆始终处于油门状态,不需要模拟倒车或停车。
                                # - FORWARD_REVERSE 使用油门值来判断车辆是向前还是向后移动,
                                #   根据情况递增或递减脉冲。在油门为零的情况下,脉冲将根据最后一个非零油门递增或递减;
                                #   实际上模拟 'coasting'(惯性滑行)。在油门降至零时,车辆仍然会有进展。
                                #   例如,在比赛中,车辆可能会滑行减速,但实际上不会停下来。
                                # - FORWARD_REVERSE_STOP 使用油门值来判断车辆是向前、向后还是停止。
                                #   这适用于速度较慢的机器人,在机器人改变方向时,例如进行 SLAM 时,
                                #   机器人将缓慢探索房间,可能需要倒车。
MM_PER_TICK = WHEEL_RADIUS * 2 * 3.141592653589793 * 1000 / ENCODER_PPR           # 单个编码器脉冲对应的行驶距离,以毫米为单位。
ODOM_SERIAL = '/dev/ttyACM0'    # 当 ENCODER_TYPE 为 'arduino' 时的串口
ODOM_SERIAL_BAUDRATE = 115200   # 串口编码器的波特率
ODOM_PIN = 13                   # 如果使用 ENCODER_TYPE=GPIO,要使用哪个 GPIO 引脚作为输入
ODOM_PIN_2 = 14                 # 差动驱动中第二个编码器的 GPIO
ODOM_SMOOTHING = 1              # 在计算速度时使用的里程计读数数量
ODOM_DEBUG = False              # 在运行过程中输出速度和距离的值

如果您使用一个兼容Arduino的微控制器来读取编码器,请在myconfig.py文件中设置ENCODER_TYPE = 'arduino'。微控制器应使用Arduino IDE刷写,并使用arduino文件夹中的其中一个示例。刷写微控制器后,可以使用串口控制台在Arduino IDE中检查示例。这些示例实现了一个按需发送编码器值和连续发送的r/p/c命令协议。命令以每行一个的形式发送(以'\n'结尾):

  • r 命令将位置重置为零
  • p 命令立即发送位置
  • c 命令启动/停止连续模式
    • 如果后面跟着一个整数,则将其作为读取之间的延迟时间(以毫秒为单位)。
    • 如果后面没有整数,则停止连续模式

在单个编码器设置中,编码器通过串口/USB端口以逗号分隔的形式发送脉冲计数和时间戳对:

{ticks},{ticksMs}

在双编码器设置中,第二个编码器的值与第一个编码器的值以分号分隔:

{ticks},{ticksMs};{ticks},{ticksMs}

tachometer.py文件实现了编码器部件,并具有__main__函数,因此可以直接运行。在激活donkey Python环境后,可以运行该文件来检查连接和确定配置参数。运行以下命令以获取可用的参数:

python donkeycar/parts/tachometer.py 

用于姿态估计和路径跟踪的里程计和运动学

编码器设置可以用于估计车辆的速度和位置。这需要在myconfig.py中进行一些配置,主要包括测量的轮子直径、轴距和轴的长度。这样可以在室内使用编码器替代GPS与路径跟踪模板一起使用。

#
# 测量的机器人属性
#
AXLE_LENGTH = 0.03     # 轴的长度;左右轮之间的距离,单位为米
WHEEL_BASE = 0.1       # 前后轮之间的距离,单位为米
WHEEL_RADIUS = 0.0315  # 轮子的半径,单位为米
MIN_SPEED = 0.1        # 最小速度,单位为米/秒;低于此速度,车辆会停止
MAX_SPEED = 3.0        # 最大速度,单位为米/秒;油门全开时的速度(1.0)
MIN_THROTTLE = 0.1     # 对应于最小速度的油门(0到1.0),低于此油门,车辆会停止
MAX_STEERING_ANGLE = 3.141592653589793 / 4  # 适用于类似汽车的机器人;最大转向角度,以弧度表示(对应于方向盘转向为-1时的轮胎角度)