FRC 2713 - Red Hawk Robotics - 2023 Build Thread

Welcome to team 2713’s 2023 build thread.

Team 2713, Red Hawk Robotics, is based out of Melrose High School in Melrose, MA. We have approximately 35-40 students and approximately 15 mentors. For machine access, we have a manual lathe, two drill presses, a band saw, a chop saw, a manual mill, several Ender 3 Pros (mostly stock config), and an X-Carve CNC (polycarb/wood only). We are lucky enough to have an incredible sheet metal sponsor, Churchill Corporation, that provides a huge amount of machining resources for our team.

During the offseason, we rebranded to Red Hawk Robotics to follow our school’s rebrand. We are still migrating some of our socials over, as a rebrand takes a lot of effort and things are not quite finalized.

We’ve had a very busy offseason:

  • Competed at 5 offseasons, playing a total of 43 additional matches
  • Completely reorganized the entire shop
  • Recycled multiple truckloads of old tools and materials
  • Dramatically increased fundraising efforts - our budget has so far doubled with room still to grow
  • Gave the pit a much needed facelift
  • Built a large custom pit cart for small parts organization
  • Completely overhauled our codebase structure in order to better support simulation, logging, and swerve.

We’ll have a couple posts about the pit cart and the software overhaul in the coming weeks.

We are cautiously optimistic about the upcoming season, where our goal is to qualify & attend the world championship in Houston, something the team has not done before. As such, our robot design and strategy will be focused around this.

We’ll be competing weeks 0, 1, and 4, at Week Zero, NE Southeast Mass, and NE Greater Boston.

24 Likes

Offseason Software Work

During the 2022 season, we achieved a huge amount of growth in our software department:

  • Reliably scoring auto routines
  • 4-5 ball auto routines (which sometimes even worked)
  • Integrating CV for the first time
  • Much more frequent usage of closed loop controls
  • Usage of WPILib Trajectory utilities

We were very proud of our growth, but we still ran into pain points and knew we had a lot of room to grow. We specifically had some frustrating moments regarding logging - there were a few matches in our second district event where our auto would seemingly randomly veer wildly off to one side. Yet during teleop, it seemed to drive totally fine. We figured it was the gyro - we had used the gyro we had found in the shop, and didn’t spend much time verifying it was in working order. We swapped it out - and still had the same problem. It wouldn’t happen every match, but it happened in a few, and it really hurt our confidence in our autos going into playoffs - I’m sure it didn’t inspire confidence from alliance captains, either. We found the issue during drive practice before DCMP - one of our Anderson crimps on a drive motor wire was a bit loose. We replaced it with the inline Wagos and the problem went away.

All that is to say - logging would have found the problem rather quickly, probably after just one occurrence of it happening.

We are very lucky to be geographically close to, and on great terms with, team 6328. They have consistently inspired us and helped us take our software one step further, and we’d like to take a second to thank them. We were extremely impressed by the capabilities of their logging and software stack, so we copied it. Oh, and we also did swerve.

Swerve Code

We are proud to release the code for our offseason swerve: GitHub - FRC2713/Robot2022-v2

This software has been tested on MK4i modules, at L3 ratio with NEOs for steering and driving, using Thrifty Encoders connected directly to the roboRIO.

Features:

  • I/O Layers have been fully integrated into working code for the first time! As a result, it should be very simple for us in future to switch between different types of hardware and simulation in code.

    • I/O layers were developed by 6328 - they have tutorial information on how they work here!
  • We’ve also finally begun simulating our robot using Glass and AdvantageScope (thanks again, 6328!). It took some effort to integrate simulation with the I/O, but it works! Now we can dedicate more time to building, since we can hope to catch more software errors by testing using the sim as well as 6328’s integrated logging tools.

  • We began using an enum-based approach to identifying SwerveModules to allow us to change the PID Controller of just one swerve module on the fly; if, say, the mechanical resistance of one module increases, gains for just that module could be increased while leaving the rest untouched.

  • We started automatically logging RevLibErrors into AdvantageScope to show anyone analyzing where and when these errors occurred, by including some stack trace. This is just one of the many things logging can help with.

  • We started using PathPlanner for our autonomous routines. We attempted to use it last year, but found that the robot wouldn’t obey our speed limits, which was, of course, a safety issue. We instead directly generated trajectories using the poses of significant field objects. This was a pain, particularly because it made changing paths very difficult (since we had to translate the points relative to their rotation - which was different depending on the object - rather than the field). Thanks to some recent changes to their API, however, the robot is consistently working with our constraints again, so we’ll be using it this year.

  • An enum-based approach to managing paths from PathPlanner was implemented which simplifies the task of switching between paths and getting their trajectories.

  • We created a motion handling class this year! All of its methods take in no parameters, and return a set of SwerveModuleStates for the robot to follow on that command loop. The swerve subsystem runs methods from the motion handler every loop based on an enum, which can then be controlled in other classes, for example using controller outputs. The current list of motion modes are as follows:

    • Trajectory - used whenever following a trajectory. It uses a TrajectoryController class we made, which can be set to particular trajectories, and which then samples the trajectory’s target pose every loop and returns the necessary ChassisSpeeds. The motion handler then converts the ChassisSpeeds into SwerveModuleStates, and returns them.
    • Full Drive - this is your standard swerve driving. Takes in the driver’s inputs, converts them into ChassisSpeeds, converts those into SwerveModuleStates, and returns them.
    • Heading Controller - Standard swerve driving, but with a twist; instead of controlling the speed of rotation directly, the driver controls the setpoint of a PID controller, which then calculates the speed of rotation.
    • Lockdown - this one’s pretty simple - just hardcodes an array of SwerveModuleStates which will stop the robot and put the wheels in a configuration which will make them difficult to push. Probably useful for defense.
    • It’s very easy to add motionModes using this model - just add an option to the enum, add a corresponding method which returns SwerveModuleStates, and change the switch case in the chassis subsystem to implement it.
  • We’ve also ventured into documentation for the first time - hopefully some of what we’ve written is a little clearer now, but we’re still open to any questions (and bugs) anyone comes across.

We’re not done yet, though - assuming we decide to continue using swerve during the main season, here are a few other things we want to look at:

  • Pathing on the fly, for example by pressing a single button to bring the robot to some game-relevant location
  • Updating odometry using CV, and just generally increasing its accuracy
  • Working out the kinks with event markers in PathPlanner, and potentially using these in our auto commands
  • Putting I/O layers on other subsystems
  • Expanding usage of the MotionHandler with game-relevant controls (maybe implementing the above-mentioned improvisatory pathing)
  • Adding Robot.goSlow() for increased precision
12 Likes

I’ve been pretty fixated on differentials for the past few weeks, so when the game was revealed, we tried very hard to make a differential elevator work for the game and the team. Unfortunately, it didn’t work out for us, but maybe it’ll work out for you:

3 Likes

Code: GitHub - FRC2713/Robot2023

CAD: Onshape

We’ll have more posts coming tomorrow (cart) and Sunday (week 1).

5 Likes

General Requirements Regarding Pit + Shop Improvements:

After finishing our competition season, we realized that, in order to actualize our robot-centric goals, we must also make pit and shop improvements. With this in mind, we outlined a few requirements:

  • Moveable Pit: Not only from truck-to-venue-to-truck, but also easily moved during DCMP/CMP playoffs.
    • Additional benefit if NE FIRST keeps CMP pit + robot “shipping service.”
  • Integrated Pit + Shop: Team members becoming accustomed to working out of the pit during the season will improve efficiency during competition.
    • Removes need to pack and unpack prior to, and post competition, respectively.
    • Lower risk of “forgetting to pack” any items; can prove detrimental with non-COTS items.
  • Better Organized Small Parts + Tool Storage: To optimize pit space, we decided on using two carts: a COTS tool cart (linked here), and a custom and/or small parts storage cart (widely influenced by this video), which will be the focus of this post.
    • Prioritizing single-sided storage containers over double-sided storage containers.
    • Custom cart gives freedom of choice with regard to which storage containers we use (w/ the additional understanding that the game, and with it the parts we use, will continue to change every year).
    • Storage that’s user friendly; NOT:
      • Bins stacked directly on top of each other.
      • Boxes inside of boxes, inside of boxes (or, in our case, FIRST-provided totes).
      • Reliance on event-provided tables.
      • Tabletop workspaces becoming a method of storage; i.e. they are not available as workspaces.

Custom Cart:

The discussion soon split between two options: a separate Custom Cart and Battery Cart, and a Custom Cart with batteries. Although we have seen teams integrate battery storage into COTS carts, we felt this could be a safety hazard, i.e. highschool students pushing a 750 lbs cart up a ramp.

We chose this Harbor Freight (HF) bin for storing small parts. It contains variably sized inner containers, and is cheaper and more widely available than other alternatives. Since the HF bins aren’t deep enough to hold larger parts (such as COTS swerve module parts…), we decided to include different sizes of sterilite bin in the Custom Cart (links: 6 qt, 15 qt, 27 qt) (thanks to 2363 for the recommendations). We chose to not use the 27 qt sterilite bins because we felt they were not as space efficient as the 6 qt and 15 qt bins.

We then designed 6 layout variations for the cart in CAD (see v.4 for final version).

Layouts with Integrated Battery & Charger Storage

HF Bins + 6 qt Sterilite Bins

HF Bins + 15 qt Sterilite Bins

HF Bins + 6 qt / 15 qt Sterilite Bins

Layouts without Integrated Battery Storage & Chargers

HF Bins + 6 qt Sterilite Bins

HF Bins + 15 qt Sterilite Bins

HF Bins + 6 qt / 15 qt Sterilite Bins

Final Design with Removable & Standardized Battery Bays:

HF Bins + 6 qt / 15 qt Sterilite Bins:

HF, 6 qt, + 15 qt sterilite bins: (FINAL DESIGN); 2x1 Aluminum L Bracket Shelves


Front view, “pit/shop mode”

Other Perspectives

|665x568.9811946222638
Isometric view, “transport mode”

|723x456.79452897607575
Back view, “pit/shop mode”

To maximize storage efficiency and the longevity of the cart, we chose the version with batteries, HF bins, 6 qt, and 15 qt Sterilite bins. We used this design as a base, keeping small parts storage the same, and changing battery storage. We made several changes to the cart’s design – notably, standardizing not only the Battery Bays (i.e. all removable, all the same size, etc) but also the shelves for the 6 qt sterilite bins (see above). We removed the right-most Battery Bay design; the design became simpler and we only substituted a 15 qt sterilite bin for a 6 qt bin. The design’s specifications are as follows:

We prioritized the Battery Bays being removable. This ensures easier transportation to non-competition events (i.e., bringing batteries to drive practice, a demo, etc.) as well as simplifying the overall structure – the CAD model and the actual building process – of the cart. There are two versions of the cart with removable Battery Bays; we chose the second version (see above) because of its simplicity. We used dado joints to help further stabilize the cart, especially since it was horizontally divided by a single piece of plywood. Instead of wooden shelves, we chose to use 2x1 (x18”) aluminum L brackets provided by our sheet-metal sponsor, Churchill Corp. This change will simplify the design and allow us to fit more storage containers. We allocated space behind the Battery Bays for a power strip, and used this mounted outlet to easily connect the power strip to external power at competition and in our lab, and avoid dealing with a cable going through external panels.

Building the Cart:

After finalizing the cart’s design in CAD, we began the process of manufacturing it. We are extremely grateful to Boulter Plywood, a local plywood supplier, for providing us with high-quality Baltic Birch plywood at a discounted price. Additionally, we’re grateful to our school’s tech-ed teacher for lending both his expertise and his classroom’s woodworking shop to this project. We used a table saw to cut individual pieces of plywood, and started routing the smaller dado joints, using this Harbor Freight router. All dados are ¼” deep and ¾” wide. We made and re-used the same router jig (pictures below) for all smaller pieces, adjusting the dimensions accordingly. Larger dados — or those on larger pieces (i.e., the top of the cart) — were cut using a mentor’s table saw with a dado-blade. On the sides of the Battery Bay, we drilled two circular holes, using a Jigsaw to connect them to create handles.

Pictures

|689x918.629904813612
Router jig for dado joints


Transporting plywood from the tech-ed shop to our shop

We then began constructing both the Battery Bays and cart without wood-glue, as a test fit. The Battery Bays are all completely “screwed-and-glued,” but we want to test the functionality of the cart before disassembling and glue-ing. We installed all of the shelves in-place, using different small jigs for spacing. We plan to continue working on the cart during build-season — hopefully ready for use by our first District Event, SE Mass in Week 1. We will update the thread with pictures and progress.

Pictures

21 Likes

Recap Week 1 of 2023 Build Season

11 Likes

An Update

We’ve been slacking, and we apologize. We’re a rapidly changing team that is currently maxing out our bandwidth on the robot.

Design

Drivetrain

We settled on swerve rather quickly, on day 2 of build. We looked at the field and the only reason that we shouldn’t do swerve that we could find was the cable protector, which we don’t believe will be detrimental to it. Additionally with how cramped the line-up process is in the community, on top of the cramping in the human player station area, we settled on swerve, with the MK4i modules we already had on hand.

We evaluated the two module configs for the MK4i - standard and high-clearance. Due to the way we’re mounting the elevator above the chassis, we aren’t able to lift the modules up and out of the chassis, as the elevator prevents it. Because of this, we opted for the high-clearance config, which allows us to drop the modules out the bottom of the chassis without interference.

We wanted to go as small as possible without jeopardizing our center of gravity - 24" or 25" felt a bit too small due to a likely higher CG this year than last, and 26" square felt “just right.” This is also the maximum size you can be if you want to fit 3 robots on the bridge, but with swerve you can simply strafe your bumpers off the edge for the couple extra inches you’ll need to make sure robots aren’t accidentally pushing against each other while trying to balance.

Pictured are a simple top guard (mostly to prevent grease from flying all over), a Spectrum Corner™, and some crush blocks to help us not crush the tube while we’re fastening the modules into place. These are all PLA+ parts. We’re running the L3 on NEOs.

The higher config does raise the belly pan, and thus the CG, though - we are already concerned about CG due to everything above the drivetrain, so we want to keep the CG as low as possible. Due to this and our sheet metal sponsor’s availability, we created the belly pot.

The belly pot rivets to the bottom of our drive rails, and lowers everything on it (battery, PDH, sparks, etc) by an additional 1.75 inches. This is currently a single piece of aluminum, but it’s not difficult to transform this into a 5-piece set of 4x aluminum brackets and 1x stainless steel belly pan if we need an even lower CG (and have the weight for it). Always have a backup plan.

We’ve laid out the electronics in such a way to minimize cable runs as best we can. We are using the VRM to power both our radio and our network switch, rather than using the REV Radio Power Module plus a Polulu regulator. The VRM is just easier for our use case. Hopefully the radio has more ports in the future. Pictured sparks are for our swerve modules plus our elevator.

Elevator

We’ve decided on a continuous (3/16” Dyneema) rigged elevator powered by 2 NEOs at ~5:1. The elevator is mounted at a 55 degree angle. The mounting for this is a rather difficult packaging problem, which is why we are using the Spectrum Corners to allow us to rivet plates to the outside of the drive rails.

We’re using some additional 2x1 to brace the upper parts of the elevator. As of now we plan on routing the wires connecting to the carriage through these 2x1’s. It’s possible we’ll mount a vision camera up here as well, but that’s still to-be-finalized, and may wind up near the belly pan. The rigging here goes both inside and outside the tubes, and is very similar to 1323 2019. We also opted for using 1x1 tubing as opposed to 2x1 for the top and bottom of our carriage. This will allow for our tensioning system (which will be mounted on the bottom of our carriage) to better align with our driving pulleys and prevent the Dyneema from going at too steep of an angle and potentially slipping.

Four-bar

Mounted to the elevator carriage is our four-bar system, which is responsible for allowing the end effector to get where it needs to be. We’ve intentionally left the four-bar-to-intake-mounting a bit abstract as we are still experimenting with intake geometry.

The sparks here are for powering both the four-bar and the end-effector. The four-bar is powered (currently) by a single NEO on a 250:1 reduction - a 100:1 planetary reduction, which powers a 16:40 RT25 belt reduction. This belt is mounted to both the four bar arms and a MAX Spline shaft, in order to power both sides on one motor. We’ve left open the possibility of adding a second motor to power the other side of the four bar, which is something we did last year and wound up saving us due to some tolerance & controls issues.

We are prioritizing modular design with the carriage-extension. Since the 4-bar/end-effector is the only part of our robot consistently extending outside of our frame-perimeter, we believe they are likely to get damaged during matches. Modularity allows us to isolate issues, replacing individual parts rather than the entire system. Last year, we ran into this issue a lot (especially with our climber) — short turn-arounds spent removing, fixing, and replacing a whole part of our robot. We hope modular design will help to prevent this.

Intake

We currently have two intakes that we are actively CADing and will manufacture. We don’t have enough signal to definitively say one is better than the other, and we have the bandwidth to design & build both, so we are going to design & build both.

Jawn-a-thin

On the left side, you’ll see a NEO 550 on a 45:1 reduction, with an output shaft that has both a pulley and a gear.

The pulley on the MAX Planetary output runs directly to the upper red roller. The gear runs to a separate axle, which is coaxial with another pulley, which connects to the lower red roller. This is in order to have both rollers powered by a single motor, but with inverted directions. The belt runs are all 1:1.

On the right side, you’ll see another NEO 550 on another 45:1 reduction that powers the output shaft with the 4" flex wheels on it. This is a 1:1 belt run.

The red plates on the outside are belt guards to prevent the belts from ever walking off or getting hit by another robot (which plagued us last year).

Marvin

The concept of Marvin is that those mid-level flex wheels are spring loaded inwards, and each half of the intake is each powered by a motor. It’s on the table to move this to a single motor powering it, but for now we’re using two. These 4" flex wheels are powered by a NEO 550 at a 2:1 reduction. We are still actively working on motor mounting and related geometry here.

Software

We’ve taken a huge amount of inspiration from 6328 over the last year, and have fully converted to the AdvantageKit hype train. The majority of our work has been on learning how to most effectively utilize simulation. We are simulating each of our mechanisms right now:

Since our elevator is at an angle and does not behave exactly the same as a normal vertical elevator, we had to subclass ElevatorSim in order to adjust the gravitational constant, resulting in AngledElevatorSim.

Our swerve modules are simulated by modeling each module as two flywheels - one for azimuth, one for driving. It works, but the MOIs are mostly just guessed and will probably be wrong on the real robot and will need re-tuning.

We’re not taking too many risks this year, and are mostly catching up to the latest on recommended approaches for things like pose estimation with April Tags.

Autonomous

One thing we are taking risks with is our autonomous path generation methodology. Since this year’s field is not rotationally symmetric, we need to do some more explicit transforms in order to account for red vs blue alliance paths. Our requirements were:

  1. Only create/maintain paths on one side of the field (e.g. blue)
  2. Use a GUI-based path creation tool (PathPlanner)
  3. Minimize the amount of “red vs blue” compensation that needs to occur during April Tag usage.

The third point is a quality-of-life requirement and is not based on any performance or math related foundations. Since we are still learning a lot about coordinate spaces in robotics, we feel it would be easiest if we had an absolute origin - in this case being the bottom-right corner of the blue alliance driver station wall. We felt it’d be easiest to understand pose-based log data if we had the same origin in every match. This may not be the case for every team, and that’s okay.

PathPlanner provides a solution for requirement #1 and #2, but the built-in transformation of trajectories from blue to red also adjusts the origin, which we do not want (but we’re sure will be a totally valid solution for most teams).

We want to manually reflect the trajectories (and states) ourselves at robotInit, in order to transform them from blue to red. However, PathPlanner’s transformation algorithm uses private fields that we can’t access, so we can’t completely transform it on our own. There are two solutions:

  1. PR PathPlanner to make private fields not private.
  2. Use reflection.

We felt adventurous, so we chose #2. We’d like to thank @came20 for helping us with this.

Effectively, we are taking each state in the trajectory and just mirroring it across the mid line to a new pose. This also requires some rotation changes and some curvature changes - some of which are private fields that we need to tell the JVM to make accessible. We then join the states to a trajectory using a constructor that is also private.

This will only crash if the API signatures change, which won’t happen during an event, as we won’t be updating PathPlanner during events. This is not recommended to most teams. That said, it fits our requirements for this year’s codebase.

Mechanism2d

Mechanism2d is great and recommended. However, we were worried about code complexity with having each subsystem update its own Mechanism2d, which may or may not be dependent on other subsystems’ Mechanism2d (mostly just at initialization time). Since we are opting for public static subsystems rather than dependency injection this year, we wrote a quick “subsystem” that reads from all the other subsystems and updates the whole Mechanism2d drawing. This class is a work in progress and will change drastically over the course of the season.

(PID tuning to be perfected later)

Overall, we are cautiously optimistic at this time. We are happy to see great teams like 3847 coming to similar conclusions as us and would like to thank them for sharing so much.

7 Likes