DigiKey Custom 3D Printed Death Racer RC Combat Tanks
2023-07-25 | By Travis Foss
License: See Original Project 3D Print Accessories 3D Printing
When DigiKey decided to exhibit at the FIRST Robotics 2023 World Championship in Houston, TX, we decided to showcase something that highlights the 3D printers, printer filaments, and printer accessories we carry. After thinking of different ideas, we decided to print two of the so-called “Death Racers” that have taken the spotlight at recent RepRap 3D printing festivals. If you aren’t familiar with what a Death Racer is, it is a 3D-printed tank with a plastic rider atop and a boom that extends from the back of the machine. There is also a game format that surrounds these machines where the drivers of them use the boom to knock the head off the riders of the other competitors. There is a switch that turns off the motor ESCs (Electronic Speed Controllers) and causes the robot to shut down when the head is knocked off. The premise is similar to Rock ‘Em Sock ‘Em Robots. The competitions typically have 20 to 30 machines competing at a time and are quite a sight to see.
Although we had not planned to attend any of the RepRap festivals, I thought this could be a fun project to show off the capabilities of the Lulzbot Printers and various 3D printing Filaments that we carry in addition to a number of the electronics that one can integrate into these Machines.
To get the files to print the robot, I subscribed to Michael Babbeley’s Patreon. I was able to download all of the original Death Racer STL’s and fusion files to build the original version of these machines. Around that time, I came across Edge Of 3D’s YouTube channel, and he had just released his own modified body for the Death Racers, which looks more similar to a Formula One car. I downloaded those files and began the printing marathon that ensued.
The treads were the first thing to print for the Death Racers. Each track requires 30 of the track STLs. We used Polymaker’s Polyflex filament in Black and True Red for the tracks, as they closely match DigiKey’s colors. A tip if you are printing TPU filament onto a PEI-coated print bed - use some adhesive on the print bed. I found out the hard way that if not used, the TPU will bond with the PEI film, and when removing the print, it will damage the bed. After putting a hole in the flexible bed, I discovered that adhesive is needed to create a barrier between the bed and the filament. The adhesive we used for the flexible filaments was Magigoo Flex formula adhesive. It worked wonderfully for this application and, as the bed cools, the Magigoo allows the part to release, making removal very easy. And afterward, only water is needed to remove the excess adhesive from the bed.
Freshly printed TPU Treads
After printing the treads, the drive gears for the wheels were printed using Polymaker Polylite PETG. It's recommended to print these with eight wall perimeters and eight top and bottom layers. After printing the drive gears, the body and rider parts were printed with 3D fuel PLA in Midnight Black and Fire Engine Red. One nice thing about building two opposite-colored Death Racers is that we could print one of every part in red and one set in black. If you are not building multiples, I recommend planning which pieces will be which color before starting printing. There are quite a few parts to print, so it can get overwhelming to figure out which part to print in which color. A nice feature included in the Patreon files is that the rider pieces are separated into two color files, one for color A and one for color B, which helps immensely as several pieces make up the rider.
Drive hubs
Another Drive Hub
More Drive hubs
While printing the parts, we made a few modifications to get the parts to fit or look correct. The first were the heads of the riders. I gave one rider a Deadpool-style head since the color scheme matched our design. The idea for the second rider came to me after speaking with some of my Coworkers. My supervisor had used a 3D scan of his head for another project, so he seemed like a perfect candidate for the rider of the second racer. While the Deadpool head required some post-processing and painting, the head of the other rider was printed in a skin-tone PLA and is one of the cleanest prints of the entire build. I didn’t have to do any post-processing on the second print. The next modified part was the boom mount for the back servo on the Death Racer. The original file called for an aluminum servo horn with a specific shape; however, while our servo came with a similarly shaped horn, it was slightly larger than the one in the original design. The downloaded files also include a Fusion 360 file of all the parts so they can be modified easily. For instance, I used Fusion 360 to modify the boom mount to perfectly fit our servo's horn.
Unfinished Deadpool head
The right part is the original Servo horn piece. Left is a test print of the newly modified piece to make sure it fits over the new servo horn.
After finishing printing all the parts, assembly began. I recommend keeping a deburring tool handy for this step. Our prints had a slight elephant’s foot, but the deburring tool works great to remove this. The deburring tool is also convenient for holes where the fit is just a little too tight. With just a couple turns of the deburring tool, the parts fit together nicely!
The modded files from Edge of 3D are designed to use heat-set inserts. To install the inserts, it works best to set the temp of the soldering iron slightly higher than the printing temp of the filament. This makes inserting the heat set insert easy as it slides into the designed hole quickly and gives a good bond between the filament and the insert. While installing the first handful of inserts, I found that I had set the temperature to low. The inserts would melt into the model; however, once light pressure was applied while tightening the screws, the inserts broke free. Also, note that you should use blue thread lock on any metal-to-metal connection. I used it on every metal-to-metal connection point except for one - the motor shaft adapter that holds the drive gear to the motor! While driving the robots during the FIRST Robotics event, these screws backed out, resulting in the loss of power to one track on each of the robots. I guess I can mark that down as a lesson learned.
Heat Set inserts in the motor mount
During the assembly, two carbon fiber rods are added between the track frames and the body to increase strength. When these were purchased, they were about 50mm too long, so they needed to be cut down. To keep the rods from splintering, I wrapped both in blue painter’s tape at the length I needed, which resulted in a clean cut. With the rods cut, they are sandwiched between the drive frame and tracks within the designated grooves in the models.
With most of the assembly complete, it came to the point I needed to hook up the electronics. I decided to add a few extras to the racers, mainly to add lights on the front bumper. In the nose of the car, a Seeed Xiao RP2040 board and two SparkFun RGB LEDs were installed. The LEDs used are addressable, so the Xiao board was programmed in the Arduino IDE using the Adafruit Neopixel library to create a few different flashing patterns. The Xiao board and LEDs are soldered to a Solderful Breadboard hidden inside the cavity in the nose of the racer, and power is controlled via a switch installed on the rider’s console.
After getting the LED’s up and running, the next thing to set up was the remote receiver and all the connections to it set up. The below picture is how I connected the motors, servos, and the power to the xiao board. Channel 1 of the ESC connects to the left track, and channel 2 is the right track. Next is the servo that controls the boom, which connects to channel 4. Channels 5 and 6 are the servos that control the left and right hands of the rider. Last, the power and ground wires from the xiao board connect to the B/VCC port. I used Deans connectors for the ESC power input wires, which is the same connector that's installed on the 2S lipo battery packs we used. I also ran the connection through the switch connected to the head and back to the ESC, so it powers down when switched off.
RC Receiver wiring
After the electronics were together, there were a few settings on the controller to control the robot in a tank-drive manner. In the menu on the controller, the Elevon setting must be switched on, which mixes the right stick motion to control channels 1 and 2 into a tank drive style control. The left stick’s side-to-side motion controls the bludger servo and doesn’t require any additional changes. The last change that was needed was to mix the arm servos with the channels 1 and 2 control to match the motion of the right stick so that the rider appears to be controlling the racer. To accomplish this, navigate into the controller’s menu and select mixes. Set channel 5 to mix with channel 1 on mix 1, and channel 6 to mix with channel 2 on mix 2. This causes the arms to move forward when the drive stick on the remote is pressed forward and backward when it was pulled back. Since the controller is limited to only 3 mixes, the last mix is to mix channel 5 with channel 3 on mix 3, which causes the arm to move on turns.
With the electronics complete and installed, it was time for the final assembly and the first test drive. The body was placed on top of the drivetrain and fastened with 10 M3 screws. However, once I had the racers together, I noticed one of the tracks had some extra resistance when driving. Upon investigation, it was discovered that the drive wheel was slightly contacting the drive frame, but with a bit of sanding and trimming the rubbing was eliminated, and the racers were fully operational.
Partially assembled Racer
Partially assembled Racer
The robots turned out great!!
Finished Robots
While I haven’t had much drive time with these racers, this is an excellent project for anyone that wants to improve their 3d printing skills. It will challenge you to get your 3d printer printing at its best. If you are looking to improve your skills, I recommend looking into this one.
https://twitter.com/i/status/1648796061501124608
(embed tweet: <blockquote class="twitter-tweet"><p lang="en" dir="ltr">FIRST Championship 2023 is officially under way and we’re loving the enthusiasm 👏. <br><br>Good luck to all teams! <a href="https://twitter.com/FRCTeams?ref_src=twsrc%5Etfw">@FRCTeams</a> <a href="https://twitter.com/FIRSTweets?ref_src=twsrc%5Etfw">@FIRSTweets</a> <br><br>Be sure to come say hi at booth #1108 in the <a href="https://twitter.com/hashtag/Robotics?src=hash&ref_src=twsrc%5Etfw">#Robotics</a> Center 👋 <a href="https://twitter.com/hashtag/FIRSTChamps?src=hash&ref_src=twsrc%5Etfw">#FIRSTChamps</a><br><br>P.s. peep the <a href="https://twitter.com/hashtag/3dprinted?src=hash&ref_src=twsrc%5Etfw">#3dprinted</a> RC car feat <a href="https://twitter.com/Kwalseth?ref_src=twsrc%5Etfw">@Kwalseth</a> 👀 <a href="https://t.co/UsQ2Ape8mP">pic.twitter.com/UsQ2Ape8mP</a></p>— DigiKey (@digikey) <a href="https://twitter.com/digikey/status/1648796061501124608?ref_src=twsrc%5Etfw">April 19, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>)
If you want to add headlights similar to what I did with these racers, here is the code I used for the Xiao microcontroller.
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
// Which pin on the Arduino is connected to the NeoPixels?
// On a Trinket or Gemma we suggest changing this to 1:
#define LED_PIN 7
// How many NeoPixels are attached to the Arduino?
#define LED_COUNT 2
#define Power 27
// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
// setup() function -- runs once at startup --------------------------------
void setup() {
// These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
// Any other board, you can remove this part (but no harm leaving it):
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
clock_prescale_set(clock_div_1);
#endif
// END of Trinket-specific code.
pinMode(Power,OUTPUT);
digitalWrite(Power, HIGH);
strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
strip.show(); // Turn OFF all pixels ASAP
strip.setBrightness(200); // Set BRIGHTNESS to about 1/5 (max = 255)
}
// loop() function -- runs repeatedly as long as board is on ---------------
void loop() {
// Fill along the length of the strip in various colors...
colorWipe(strip.Color(255, 0, 0), 100); // Red
colorWipe(strip.Color( 0, 255, 0), 100); // Green
colorWipe(strip.Color( 0, 0, 255), 100); // Blue
// Do a theater marquee effect in various colors...
// theaterChase(strip.Color(127, 127, 127), 150); // White, half brightness
theaterChase(strip.Color(127, 0, 0), 100); // Red, half brightness
theaterChase(strip.Color( 0, 0, 127), 100); // Blue, half brightness
rainbow(10); // Flowing rainbow cycle along the whole strip
theaterChaseRainbow(50); // Rainbow-enhanced theaterChase variant
redFadeIn(5);
redFadeOut(2);
policeLights(25);
redFadeIn(10);
redFadeOut(10);
}
// Some functions of our own for creating animated effects -----------------
// Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single 'packed' 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(uint32_t color, int wait) {
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
strip.setPixelColor(i, color); // Set pixel's color (in RAM)
strip.show(); // Update strip to match
delay(wait); // Pause for a moment
}
}
// Theater-marquee-style chasing lights. Pass in a color (32-bit value,
// a la strip.Color(r,g,b) as mentioned above), and a delay time (in ms)
// between frames.
void theaterChase(uint32_t color, int wait) {
for(int a=0; a<10; a++) { // Repeat 10 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
// 'c' counts up from 'b' to end of strip in steps of 3...
for(int c=b; c<strip.numPixels(); c += 3) {
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
}
// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow(int wait) {
// Hue of first pixel runs 5 complete loops through the color wheel.
// Color wheel has a range of 65536 but it's OK if we roll over, so
// just count from 0 to 5*65536. Adding 256 to firstPixelHue each time
// means we'll make 5*65536/256 = 1280 passes through this loop:
for(long firstPixelHue = 0; firstPixelHue < 5*65536; firstPixelHue += 256) {
// strip.rainbow() can take a single argument (first pixel hue) or
// optionally a few extras: number of rainbow repetitions (default 1),
// saturation and value (brightness) (both 0-255, similar to the
// ColorHSV() function, default 255), and a true/false flag for whether
// to apply gamma correction to provide 'truer' colors (default true).
strip.rainbow(firstPixelHue);
// Above line is equivalent to:
// strip.rainbow(firstPixelHue, 1, 255, 255, true);
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames.
void theaterChaseRainbow(int wait) {
int firstPixelHue = 0; // First pixel starts at red (hue 0)
for(int a=0; a<30; a++) { // Repeat 30 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
// 'c' counts up from 'b' to end of strip in increments of 3...
for(int c=b; c<strip.numPixels(); c += 3) {
// hue of pixel 'c' is offset by an amount to make one full
// revolution of the color wheel (range 65536) along the length
// of the strip (strip.numPixels() steps):
int hue = firstPixelHue + c * 65536L / strip.numPixels();
uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
}
}
}
void redFadeIn(int fadeInSpeed){
//for (int k=0; k<fadeInSpeed; k++){
for (int j=0; j<256; j++){
strip.fill(strip.Color(0,j,0));
strip.show();
delay(fadeInSpeed);
}
//}
}
void redFadeOut(int fadeOutSpeed){
//for (int k=0; k<fadeOutSpeed; k++){
for (int j=255; j>=0; j--){
strip.fill(strip.Color(0,j,0));
strip.show();
delay(fadeOutSpeed);
}
//}
}
void policeLights(int numFlashes){
for (int j=0; j<numFlashes; j++){
strip.fill(strip.Color(0,255,0));
strip.show();
delay(100);
strip.fill(strip.Color(0,0,0));
strip.show();
delay(1);
strip.fill(strip.Color(0,0,255));
strip.show();
delay(100);
strip.fill(strip.Color(0,0,0));
strip.show();
delay(1);
}
}
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.
Visit TechForum