iMurdockUnit - An External IMU Enclosure

Background

The Problem

Over our first three competitions, team 10809 Crow Force sacrificed points during autonomous and tele-op when our robot became disoriented, causing failures in autonomous trajectory sequences and field-centric driver control. These failures seemed to coincide with collisions between exposed metal on our robot and other conductive objects on the field such as the 2023-'24 CENTERSTAGE™ game's truss supports and other robots.

By finding a way to reproduce failures with truss contact and then printing Inertial Measurement Unit (IMU) orientation telemetry to the driver hub, we observed our gyroscope and accelerometer readings drop to all zeros after metal contact that would persist until repowering the robot. After reading FIRST's article “Managing Electrostatic Discharge Effects”, we learned that these IMU flatlines could result from ESD: electrostatic discharge. The FIRST Tech Challenge Blog's 2023-11-21 post “Unexpected IMU Reset” lead us to suspect REV Robotics' 2022-09-23 IMU hardware changes made to REV-31-1595 Control Hubs. We tested this hypothesis by switching our robot's control hub with an older model and observing a reduction in IMU resets. Unfortunately, older generation control hubs are a luxury of established teams and they won't survive the playfield forever.

Note: To determine which type of IMU your control hub contains without knowing its manufacture date, see the control hub's web interface as explained by REV's IMU documentation.


Existing Solutions

If your robot suffers from similar IMU issues or other electrical failures that might be caused by ESD, try these existing solutions first. Combine them to build up “defense in depth”, layering redundant protections that are less likely to all fail at once.


Our Solution

Once your team has applied the previous suggestions for mitigating static, your new control hub's IMU may still reset when shocked. Fortunately, external IMU sensor boards using the same chip as original control hubs can still be purchased! Read on for a simple guide to buying, assembling, attaching, and configuring a replacement IMU in a 3D-printed enclosure designed by team 10809 Crow Force and the mentors of Sage Creek High School.

A 3D render of the iMurdockUnit
                pressed over the center hump of a control hub with connectors facing upwards. A
                rectangular red cap labeled “IMU” is bolted onto the iMurdockUnit. A 3D render of the
                bottom of an iMurdockUnit revealing several labels and logos: FTC Team 10809 Crow
                Force, SCHS, and Carlsbad Educational Foundation.

Design Goals

Hardware

Required Tools

To assemble an iMurdockUnit, you will use the following tools:

Required Materials

One iMurdockUnit is made from the following components:


Assembly Instructions

Warning: Safety first. Wear safety glasses when cutting wire or while soldering, and be careful with the cutting end of wire cutters and wire strippers.

  1. Begin 3D printing the base and cap pieces: STEP file, STL file.

  2. Use wire cutters to cut the sensor cable, leaving about 10cm of cable connected to the JST PH4 connector that plugs into control or expansion hubs. Discard the rest of the cable.

  3. At the cut end of the remaining sensor cable, pull the cable's individual wires apart by about 2cm so that end appears frayed.

  4. Use wire strippers to expose about 4mm of copper from wires at the sensor cable's frayed end.

  5. In a well ventilated area, use a soldering iron and lead-free solder to connect the following stripped sensor cable wires to the Adafruit 2472 IMU breakout board:

    Note: Don't match the photo; it is only for reference matching wire colors to breakout board pads. In the iMurdockUnit, these wires must come out the top of the breakout board.

    • Red: Vin
    • Black: GND
    • White: SDA
    • Blue: SCL
    Color coded jumper wires plugged into
                    header pins that have been soldered into an Adafruit 2472 IMU breakout
                    board.

    Use this technique for each wire:

    1. Insert the stripped end of the wire through the top of the board (the side labeled “BNO055”) until the wire's insulation almost contacts the board.

      Note: Do not tin the wire first, or else you may bend unseen wire strands.

    2. Apply solder where the wire protrudes from the bottom, being careful not to connect with neighboring pads.

    3. Trim excess wire from the solder blob.

  6. Wait for both 3D printed parts from step 1 to complete, and remove any scaffolding.

  7. Use super glue to affix four M4 nyloc nuts into the corner slots of the smaller 3D printed cap piece labeled “IMU”. With the lettering facing upwards, the nuts' threaded sides should face downwards. Be careful not to get super glue inside the threads.

  8. Set the IMU breakout board onto the four tapered alignment pins within the larger 3D printed base's cutout. Centered within those pins is an engraving of a small rectangle with a dot in one corner; Locate the breakout board's black IMU chip with white dot, and match their orientations. Labels on the breakout board should be upside down compared to those on the 3D printed part.

    The IMU breakout board
                    resting on four alignment pins on the top of a 3D printed iMurdockUnit base
                    piece. Labels engraved into the two pieces are vertically flipped.
  9. The sensor cable should extend from the IMU breakout board over a channel in the larger 3D printed base. Align the cable with this channel and then press the smaller 3D printed cap on top with text from both 3D printed pieces in the same orientation. Maintain pressure to constrain the sandwiched IMU and cable while threading four button-cap M4 screws from the bottom of the base through the cap; Tighten the screws evenly, and do not over-tighten them. The following cut-away rendering illustrates how the sensor cable should fold between channels in the 3D printed parts to create strain relief.

    A 3D
                    rendered cut-away view of how the iMurdockUnit's 3D printed base and cap
                    sandwich the IMU breakout board and its soldered cable. The cable passes through
                    a snaking tunnel that acts as strain relief once tightened.

Installation

The assembled iMurdockUnit rides on a control or expansion hub's orange hump with diagonal white stripe. Rotate the iMurdockUnit so that its sensor cable extends towards the hub's I2C ports. Once aligned, press the iMurdocUnit down firmly onto the hub. Lastly, plug its dangling sensor wire into the hub's I2C port 1, 2, or 3 connector.

Note: Port 0 must not be used because it already connects to the hub's internal IMU. The Java class com.qualcomm.robotcore.hardware.IMU prefers to connect with the internal IMU if it and the iMurdockUnit external IMU are connected to the same I2C port.

An assembled iMurdockUnit mounted
            onto a powered expansion hub and connected to the I2C 1 port.

Software

Driver Station

It is very easy to get your external IMU to talk to your robot controller. Below are instructions on how to configure the external IMU using your connected driver station.


Disable Internal IMU

First, disable the built-in internal IMUs from your control hub using a connected driver station:

  1. At the driver station's main screen, tap the three-dots button at the top right and select “Configure Robot”.

    The Driver Station's “Robot Configuration” screen listing two available
                    configurations for editing: “2023_2024” and “camera”.
  2. Tap the “Edit” button of your existing robot configuration.

    The Driver Station's “Robot Configuration” screen after opening the
                    “2023_2024” configuration for editing. Two USB devices are listed for this
                    configuration: “Webcam 1” and “Control Hub Portal”.
  3. Tap the “Control Hub Portal” within your robot configuration to see its connected control and expansion hubs.

    The Driver Station's “Robot Configuration” screen after selecting the USB
                    device named “Control Hub Portal”. Two contained devices are listed: “Expansion
                    Hub 2” and “Control Hub”.
  4. Tap “Control Hub” to view categories of connected peripherals.

    The Driver Station's “Robot Configuration” screen after selecting the
                    “Control Hub” entry within “Control Hub Portal”. The first five visible
                    categories of connected peripherals are “Analog Input Devices”, “I2C Bus 0”,
                    “I2C Bus 1”, “I2C Bus 2”, and “I2C Bus 3”.
  5. Tap “I2C Bus 0” to configure sensors connected to the first communications channel. The control hub's internal IMU is hardwired to this I2C bus.

  6. Look for any entries of “REV Control Hub IMU” and disable them by selecting “Nothing”.

    Note: Do not add your external IMU on this I2C bus, since the unified IMU interface code for reading measurements will ignore your configuration and try to talk to the original internal IMU instead. See the next section for adding your external IMU to a different I2C bus.

    The Driver Station's “Robot Configuration” screen after selecting “I2C Bus
                    0” within “Control Hub”. In the two-column table of port numbers and associated
                    attached I2C devices, port zero has been assigned the device type “Nothing”.

Add External IMU

Second, add the new external IMU to a control or expansion hub:

  1. Now go to I2C Bus 1 and add an “Adafruit IMU”.

    The Driver Station's “Robot Configuration” screen after returning to the
                    previous “Control Hub” screen and selecting “I2C Bus 1” instead. Port zero has
                    been assigned the device type “Adafruit IMU”.
  2. Name your external Adafruit IMU sensor to match how your code gets a reference to it (such as using hardwareMap.get in Java). In the next section's code sample, we will use the name “imu”.

    The Driver Station's “Robot Configuration” screen after renaming the
                    “Adafruit IMU” device on port zero of “I2C Bus 1” to “imu”.

Sample Code

The code below shows how to setup your new IMU. Make the name of your imu matches the name in IC Bus 2 slot on your drive hub. Another thing to note is the Orientation we have given about our IMU. This changes depending on how you have your external IMU positioned.

package org.firstinspires.ftc.teamcode;

import com.qualcomm.hardware.rev.RevHubOrientationOnRobot;
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.hardware.IMU;

import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit;
import org.firstinspires.ftc.robotcore.external.navigation.AxesOrder;
import org.firstinspires.ftc.robotcore.external.navigation.AxesReference;


@TeleOp(name = "External IMU Test", group = "Teleop")
public class ExternalIMU extends LinearOpMode {
    public IMU imu;

    public void runOpMode() throws InterruptedException {
        //Set up external IMU from I2C bus 1
        imu = hardwareMap.get(IMU.class, "imu");
        IMU.Parameters imuParameters;

        //Parameters for IMU
        imuParameters = new IMU.Parameters(
            new RevHubOrientationOnRobot(
                //The iMurdockUnit holds its external IMU in the same orientation
                //as an internal IMU, so you can copy your original values here.
                RevHubOrientationOnRobot.LogoFacingDirection.UP,
                RevHubOrientationOnRobot.UsbFacingDirection.BACKWARD
            )
        );

        imu.initialize(imuParameters);

        //Reset left-to-right rotation
        imu.resetYaw();

        waitForStart();
        while (opModeIsActive()) {
            telemetry.addData("🧭 IMU Rotation (degrees)", getAngle());
            telemetry.update();
        }
    }

    public double getAngle() {
        return imu.getRobotOrientation(AxesReference.EXTRINSIC, AxesOrder.ZYX,
            AngleUnit.DEGREES).firstAngle;
    }
}