故障排除

排除完全故障

有很多事情会导致你的机器人做完全错误的事情。下面的清单包含了一些常见的错误。

  • 我的机器人不动了

    • 你真的在输出给你的马达输出吗?

    • driver station是否出现了MalformedSplineException?如果是,请转到下面有关MalformedSplineException的部分。

    • 您的轨迹是否太短或有单位错误?

  • 我的机器人沿着轨迹移动却不停摆动,朝向另一个方向。

    • 轨迹的起点和终点的朝向是否有错误?

    • 你的机器人陀螺仪是否重置了错误的方向?

    • 你是否将reverse flag错误设置?

    • 陀螺仪角度是设定顺时针为正吗?如果是这样,则应该反过来。

  • 我的机器人只是沿着直线行驶,即使它应该转弯。

    • 你的陀螺仪是否设置正确并返回好的数据?

    • 你是否使用正确的单位将陀螺仪航向传递到里程表对象?

    • 轨道宽度正确吗?它的单位正确吗?

  • 我的driver station显示“MalformedSplineException”,但是机器人不动。

    • 你是否将reverse flag错误设置?

    • 你是否有两个航路点非常接近且朝向相反?

    • 你是否有两个具有相同(或几乎相同)坐标的航路点?

  • 我的机器人移动得太远了。

    • 你的编码器单位转换设置正确吗?

    • 你的编码器连接了吗?

  • 我的机器人基本上能做正确的事情,但有一点不准确。

    • 转到下一部分。

解决性能不佳的问题

备注

本节主要涉及对轨迹跟踪性能不佳,例如一米的误差,进行故障排除,而不是像编译错误,机器人不停转向并朝错误的方向或”MalformedSplineException’’那样的灾难性故障。

备注

本节专为差速驱动机器人的而设计,但是大多数想法都可以适用于转向驱动或麦克纳姆转向。

不良的轨迹跟踪性能可能难以排除。虽然轨迹生成器和跟随器的目的是易于使用和卓越的表现,有情况下,机器人的表现不如预期。轨迹产生器和跟随器有很多需要调节的旋钮和运动部件,因此很难知道从哪里开始,特别是很难从机器人的大致运动中找到轨迹问题的根源。

因为很难定位异常轨迹生成器和追踪器的层次,所以对于一般跟踪性能较差的情况(如机器人偏离几英尺或超过20度),建议采用一种系统的、逐层的方法。以下是你应该做的步骤的顺序;遵循这个顺序是很重要的,这样您就可以孤立不同步骤的效果。

备注

The below examples put diagnostic values onto NetworkTables. The easiest way to graph these values is to use Shuffleboard’s graphing capabilities.

核查里程表

如果您的里程表不正确,则Ramsete控制器可能会发生异常,因为它会根据您的里程表认为机器人的位置来修改机器人的目标速度。

备注

Sending your robot pose and trajectory to field2d can help verify that your robot is driving correctly relative to the robot trajectory.

  1. 设置代码以记录每次里程表更新后机器人的位置:

NetworkTableEntry m_xEntry = NetworkTableInstance.getDefault().getTable("troubleshooting").getEntry("X");
NetworkTableEntry m_yEntry = NetworkTableInstance.getDefault().getTable("troubleshooting").getEntry("Y");

@Override
public void periodic() {
    // Update the odometry in the periodic block
    m_odometry.update(Rotation2d.fromDegrees(getHeading()), m_leftEncoder.getDistance(),
        m_rightEncoder.getDistance());

    var translation = m_odometry.getPoseMeters().getTranslation();
    m_xEntry.setNumber(translation.getX());
    m_yEntry.setNumber(translation.getY());
}
NetworkTableEntry m_xEntry = nt::NetworkTableInstance::GetDefault().GetTable("troubleshooting")->GetEntry("X");
NetworkTableEntry m_yEntry = nt::NetworkTableInstance::GetDefault().GetTable("troubleshooting")->GetEntry("Y");

void DriveSubsystem::Periodic() {
    // Implementation of subsystem periodic method goes here.
    m_odometry.Update(frc::Rotation2d(units::degree_t(GetHeading())),
                        units::meter_t(m_leftEncoder.GetDistance()),
                        units::meter_t(m_rightEncoder.GetDistance()));

    auto translation = m_odometry.GetPose().Translation();
    m_xEntry.SetDouble(translation.X().value());
    m_yEntry.SetDouble(translation.Y().value());
}
  1. 布置一条与您的机器人平行的卷尺,然后沿着卷尺将您的机器人推出约一米。沿Y轴布置一个卷尺并重新开始,将您的机器人沿X轴推一米,沿Y轴推一米,形成一个粗糙的弧度。

  2. Compare X and Y reported by the robot to actual X and Y. If X is off by more than 5 centimeters in the first test then you should check that you measured your wheel diameter correctly, and that your wheels are not worn down. If the second test is off by more than 5 centimeters in either X or Y then your track width (distance from the center of the left wheel to the center of the right wheel) may be incorrect; if you’re sure that you measured the track width correctly with a tape measure then your robot’s wheels may be slipping in a way that is not accounted for by track width, so try increasing the track width number or measuring it programmatically.

核查前馈

如果前馈不良,则机器人各侧的P控制器也将无法跟踪,并且 differentialDriveVoltageConstraint不会精确地限制机器人的加速度。 我们主要想关闭车轮的P控制器,以便我们可以单独测试前馈。

  1. 首先,必须为每个车轮设置禁用P控制器。将每个控制器的P增益设置为0。在RamseteCommand示例中,您可以将kPDriveVel设置为0:

123            new PIDController(DriveConstants.kPDriveVel, 0, 0),
124            new PIDController(DriveConstants.kPDriveVel, 0, 0),
81      frc::PIDController{DriveConstants::kPDriveVel, 0, 0},
82      frc::PIDController{DriveConstants::kPDriveVel, 0, 0},
  1. Next, we want to disable the Ramsete controller to make it easier to isolate our problematic behavior. To do so, simply call setEnabled(false) on the RamseteController passed into your RamseteCommand:

RamseteController m_disabledRamsete = new RamseteController();
m_disabledRamsete.setEnabled(false);

// Be sure to pass your new disabledRamsete variable
RamseteCommand ramseteCommand = new RamseteCommand(
    exampleTrajectory,
    m_robotDrive::getPose,
    m_disabledRamsete,
    ...
);
frc::RamseteController m_disabledRamsete;
m_disabledRamsete.SetEnabled(false);

// Be sure to pass your new disabledRamsete variable
frc2::RamseteCommand ramseteCommand(
  exampleTrajectory,
  [this]() { return m_drive.GetPose(); },
  m_disabledRamsete,
  ...
);
  1. 最后,我们需要记录所需的车轮速度和实际的车轮速度(如果您使用Shuffleboard,或者您的绘图软件具有该功能,则应将实际速度和所需速度记录在同一张图表上)

var table = NetworkTableInstance.getDefault().getTable("troubleshooting");
var leftReference = table.getEntry("left_reference");
var leftMeasurement = table.getEntry("left_measurement");
var rightReference = table.getEntry("right_reference");
var rightMeasurement = table.getEntry("right_measurement");

var leftController = new PIDController(kPDriveVel, 0, 0);
var rightController = new PIDController(kPDriveVel, 0, 0);
RamseteCommand ramseteCommand = new RamseteCommand(
    exampleTrajectory,
    m_robotDrive::getPose,
    disabledRamsete, // Pass in disabledRamsete here
    new SimpleMotorFeedforward(ksVolts, kvVoltSecondsPerMeter, kaVoltSecondsSquaredPerMeter),
    kDriveKinematics,
    m_robotDrive::getWheelSpeeds,
    leftController,
    rightController,
    // RamseteCommand passes volts to the callback
    (leftVolts, rightVolts) -> {
        m_robotDrive.tankDriveVolts(leftVolts, rightVolts);

        leftMeasurement.setNumber(m_robotDrive.getWheelSpeeds().leftMetersPerSecond);
        leftReference.setNumber(leftController.getSetpoint());

        rightMeasurement.setNumber(m_robotDrive.getWheelSpeeds().rightMetersPerSecond);
        rightReference.setNumber(rightController.getSetpoint());
    },
    m_robotDrive
);
auto table =
    nt::NetworkTableInstance::GetDefault().GetTable("troubleshooting");
auto leftRef = table->GetEntry("left_reference");
auto leftMeas = table->GetEntry("left_measurement");
auto rightRef = table->GetEntry("right_reference");
auto rightMeas = table->GetEntry("right_measurement");

frc::PIDController leftController(DriveConstants::kPDriveVel, 0, 0);
frc::PIDController rightController(DriveConstants::kPDriveVel, 0, 0);
frc2::RamseteCommand ramseteCommand(
    exampleTrajectory, [this]() { return m_drive.GetPose(); },
    frc::RamseteController(AutoConstants::kRamseteB,
                            AutoConstants::kRamseteZeta),
    frc::SimpleMotorFeedforward<units::meters>(
        DriveConstants::ks, DriveConstants::kv, DriveConstants::ka),
    DriveConstants::kDriveKinematics,
    [this] { return m_drive.GetWheelSpeeds(); }, leftController,
    rightController,
    [=](auto left, auto right) {
        auto leftReference = leftRef;
        auto leftMeasurement = leftMeas;
        auto rightReference = rightRef;
        auto rightMeasurement = rightMeas;

        m_drive.TankDriveVolts(left, right);

        leftMeasurement.SetDouble(m_drive.GetWheelSpeeds().left.value());
        leftReference.SetDouble(leftController.GetSetpoint());

        rightMeasurement.SetDouble(m_drive.GetWheelSpeeds().right.value());
        rightReference.SetDouble(rightController.GetSetpoint());
    },
    {&m_drive});
  1. 在各种轨迹(曲线和直线)上运行机器人,并通过查看NetworkTables中的图表来检查实际速度是否跟踪所需速度。

  2. If the desired and actual are off by a lot then you should check if the wheel diameter and encoderEPR you used for system identification were correct. If you’ve verified that your units and conversions are correct, then you should try recharacterizing on the same floor that you’re testing on to see if you can get better data.

核查P增益

如果您完成了上一步,并且问题消失了,那么可能会在后续步骤之一中找到您的问题。 在此步骤中,我们将核查车轮的P控制器是否已正确调整。如果您使用的是Java,那么我们要关闭Ramsete,以便我们可以自己查看PF控制器。

  1. 除了必须将P增益重新设置为之前的非零值之外,您必须重新使用记录实际速度与所需速度的上一步中的所有代码(如果使用Java,则禁用Ramsete的代码)。

  2. 在各种轨迹上再次运行机器人,并检查您的实际图形与所需图形之间是否相符。

  3. 如果图形看起来不好(即实际速度与期望的速度有很大不同),则应尝试调整P增益并重新运行测试轨迹。

核查约束

备注

确保此步骤的P增益不为零,并且仍在前面的步骤中添加了日志记录代码。如果您使用的是Java,则应删除代码以禁用Ramsete。

如果您的准确性问题在上述所有步骤中仍然存在,则说明您的约束可能存在问题。以下是调整不良时不同可用约束出现问题的列表。

一次测试一个约束!删除其他约束,调整剩下的一个约束,并对每个要使用的约束重复该过程。以下清单假定您一次仅使用一个约束。

  • DifferentialDriveVoltageConstraint:

    • 如果您的机器人加速非常慢,则该约束的最大电压可能太低。

    • If your robot doesn’t reach the end of the path then your system identification data may problematic.

  • DifferentialDriveKinematicsConstraint:

    • 如果机器人的前进方向错误,则可能是最大动力传动系统侧向速度太低或太高。唯一方法是调整最大速度并查看会发生什么。

  • CentripetalAccelerationConstraint:

    • 如果您的机器人的航向错误,那么这可能是罪魁祸首。如果您的机器人似乎转弯不充分,则应增加最大向心加速度,但如果机器人转弯时转弯太快,则应减小最大向心加速度。

检查轨迹航路点

您的轨迹本身可能不太容易追踪。尝试移动航路点(以及航路点的标题,如果适用),并减少急转弯。