YouRobotics
Published

Refinement of a Cheap Drift Car

In this article I will talk about my project to finalize a cheap drift car. I will make a musical drift car out of a dead toy with animated

AdvancedShowcase (no instructions)102
Refinement of a Cheap Drift Car

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×2
Servo MG90D
×1
HC-12
×2
Board with addressable LEDs
×2
Wires
×1
Speed ​​regulator
×1
Player DY-SV5W
×1
Flash Memory Card, MicroSD Card
Flash Memory Card, MicroSD Card
×1
Speaker AIYIMA 5W 4 om
×1
Racks for a column
×1
Hardware for the column and brass racks
×1
LEDs white 5 mm
×2
LEDs white 3 mm
×4
LEDs red 5mm
×2
Resistors 100 ohm - 6 pcs, 150 ohm - 2 pcs, 200 ohm - 1 pc, 10 kOhm - 1 pc, 150 ohm - 1 piece, 160 ohm - 1 piece
×1
Connectors XH 2.54
×1
Connector JST SM 2.54
×2
Printed circuit boards
×1
Charging board TP4056 with step-up DC-DC converter
×1
CJMCU-103
×2
Two-color LED with a common cathode
×1
DIP Buttons
×2
LiPo 400mA
×1
Li-ion NCR 18650
×3
BMS 3S with balancing
×1

Story

Read more

Custom parts and enclosures

plate_for_cjmcu-103_yP4P8MvPZ1.stl

remote_control_antenna_ySydmArJba.stl

rudder_pin_YxLKPtcsfK.stl

servo_spacer_4Lv5h3iWKI.stl

spacer_for_servo_stand_gOSQ6B9HhA.stl

speaker_stand_aQeK2NqzXn.stl

throttle_pin_nzPN5srCpD.stl

Schematics

arduino_poS6N5m3bp.jpg

headlight_connection_BwD88bTnR5.jpg

power_board_rUtj6nBXgE.jpg

remote_controller_UB09ALve22.jpg

Code

DriftCar.ino

C/C++
//Settings
#define MUSIC_OFF_ON_COMMAND 1
#define MUSIC_NEXT_COMMAND 2
#define ON_OFF_BACKLIGHT 3
#define NEXT_ILLUMINATION 4
#define NUMBER_OF_BACKLIGHT_MODES 7 //Number of backlight modes
#define CORNER_CORRECTION -11 //(-)
#define CENTER_ANGLE 90 CORNER_CORRECTION //Center wheel position
#define MAX_ANGLE 124 //Maximum steering angle
#define MIN_ANGLE 44 //Minimum steering angle

//Libraries
#include <avr/wdt.h>
#include <Arduino.h>
#include "DYPlayerArduino.h"
#include <SoftwareSerial.h>
#include <Servo.h>

#include <LiquidCrystal_I2C.h>

SoftwareSerial mySerial(9, 8); // RX, TX
DY::Player player(&mySerial);
Servo servo;
Servo motor;

#define LEDPIN 2
#define NUMLEDS 8     //Number of LEDs
#include <microLED.h>
#include <FastLEDsupport.h>
microLED<NUMLEDS, LEDPIN, MLED_NO_CLOCK, LED_WS2818, ORDER_GRB, CLI_AVER> strip;

extern CRGBPalette16 myRedWhiteBluePalette;
extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM;

//Pins
#define M_REGULATOR 3
#define RUDDER_SERVO 6
#define REVERSE_LEDS 7


boolean playerStatus = 0;
boolean triggerFlag = 0;
boolean musicStatus = 0;
boolean backlightStatus = 0;
boolean noData = 0;
boolean emergencyStop = 0;

int backlightMode = 0;

unsigned long ledTimer = 0;
unsigned long noDataTimer = 0;

struct Str {
  uint8_t direction;
  int16_t speed;
  uint8_t angle;
  uint8_t command;
};

Str buf;

void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
  servo.attach(RUDDER_SERVO);
  motor.attach(M_REGULATOR);

  pinMode(REVERSE_LEDS, OUTPUT);

  player.begin();
  player.setVolume(95); //Set the volume to 95%
  player.setCycleMode(DY::PlayMode::Random);
  player.stop();

  strip.setBrightness(64);
  buf.angle = CENTER_ANGLE;

  wdt_enable(WDTO_1S);
}

void ReceiveData() {
  Serial.readBytes((byte*)&buf, sizeof(buf));
}

void PlayerControl(int command) {
  servo.detach();
  motor.detach();

  if (command == 0) {
    musicStatus = 0;  //Turn off the music
    player.stop();
  }

  if (command == 1) {
    musicStatus = 1;  //Turn on the music
    player.play();
  }

  if (command == 2 && musicStatus == 1) {
    player.next();  //Next music
  }

  motor.attach(M_REGULATOR);
  servo.attach(RUDDER_SERVO);
}

void loop() {
  ControlCar();

  if (Serial.available() > 0) {
    ReceiveData();
    noData = 0;
    emergencyStop = 0;
  } else {
    if (noData == 0) {
      noDataTimer = millis();
      noData = 1;
    }
    if (noData == 1 && emergencyStop == 0 && (millis() - noDataTimer) > 500) {
      buf.direction = 0;
      buf.speed = 1500;
      player.stop();
      offLeds(); //Turn off backlight
      backlightMode = 0;
      emergencyStop = 1;
    }
  }

  carBacklight();
  wdt_reset();
}

void ControlCar() {
  if (buf.direction == 0) {
    motor.writeMicroseconds(1500);
    digitalWrite(REVERSE_LEDS, LOW);
  }

  if (buf.direction == 1) {
    motor.writeMicroseconds(buf.speed);
    digitalWrite(REVERSE_LEDS, LOW);
  }

  if (buf.direction == 2) {
    motor.writeMicroseconds(buf.speed);
    digitalWrite(REVERSE_LEDS, HIGH);
  }

  if (buf.angle >= MAX_ANGLE) {
    buf.angle = MAX_ANGLE;
  }

  if (buf.angle <= MIN_ANGLE) {
    buf.angle = MIN_ANGLE;
  }

  servo.write(buf.angle); //Turning the servo

  if (buf.command == MUSIC_OFF_ON_COMMAND && triggerFlag == 0) { //Turning music on and off
    triggerFlag = 1;
    playerStatus = 1 - playerStatus;
    PlayerControl(playerStatus);
  }

  if (buf.command == MUSIC_NEXT_COMMAND && triggerFlag == 0) { //Switching music
    triggerFlag = 1;
    PlayerControl(2);
  }

  if (buf.command == 3 && triggerFlag == 0) { //Turning the backlight on and off
    triggerFlag = 1;
    backlightStatus = backlightStatus - 1;
    backlightMode = 1;

    ledTimer = millis();

    if (backlightStatus == 0) {
      offLeds(); //Turn off the backlight
      backlightMode = 0;
    }
  }

  if (buf.command == NEXT_ILLUMINATION && triggerFlag == 0 && backlightStatus == 1) { //Switching backlight mode
    triggerFlag = 1;
    backlightMode++;
    if (backlightMode > NUMBER_OF_BACKLIGHT_MODES) {
      backlightMode = 1;
    }

  }

  if (buf.command == 0 && triggerFlag == 1) {
    triggerFlag = 0;
  }

}

void offLeds() {
  strip.leds[0] = mBlack;
  strip.leds[1] = mBlack;
  strip.leds[2] = mBlack;
  strip.leds[3] = mBlack;
  strip.leds[4] = mBlack;
  strip.leds[5] = mBlack;
  strip.leds[6] = mBlack;
  strip.leds[7] = mBlack;
  strip.show();
}

void carBacklight() {
  if ( ((millis() - ledTimer) > 40) && backlightStatus == 1 ) {
    motor.detach();
    static byte count = 0;
    static int count2 = 0;
    count = count + 4;
    count2 += 10;
    strip.begin();
    for (int i = 0; i < NUMLEDS; i++) {
      switch (backlightMode) {
        case 1: //Green
          strip.leds[0] = mGreen;
          strip.leds[1] = mGreen;
          strip.leds[2] = mGreen;
          strip.leds[3] = mGreen;
          strip.leds[4] = mGreen;
          strip.leds[5] = mGreen;
          strip.leds[6] = mGreen;
          strip.leds[7] = mGreen;
          strip.show();
          break;

        case 2: //Blue
          strip.leds[0] = mBlue;
          strip.leds[1] = mBlue;
          strip.leds[2] = mBlue;
          strip.leds[3] = mBlue;
          strip.leds[4] = mBlue;
          strip.leds[5] = mBlue;
          strip.leds[6] = mBlue;
          strip.leds[7] = mBlue;
          strip.show();
          break;

        case 3: //Red
          strip.leds[0] = mRed;
          strip.leds[1] = mRed;
          strip.leds[2] = mRed;
          strip.leds[3] = mRed;
          strip.leds[4] = mRed;
          strip.leds[5] = mRed;
          strip.leds[6] = mRed;
          strip.leds[7] = mRed;
          strip.show();
          break;

        case 4:
          strip.send(CRGBtoData(ColorFromPalette(RainbowColors_p, count + i * 3, 255, LINEARBLEND)));
          break;

        case 5:
          strip.send(CRGBtoData(ColorFromPalette(RainbowStripeColors_p, count + i * 3, 255, NOBLEND)));
          break;

        case 6:
          strip.send(CRGBtoData(ColorFromPalette(RainbowColors_p, count + i * 3, 255, LINEARBLEND)));
          break;

        case 7:
          strip.send(CRGBtoData(ColorFromPalette(myRedWhiteBluePalette_p, count + i * 3, 255, NOBLEND)));
          break;

      }
    }
    strip.end();
    motor.attach(M_REGULATOR);
    ledTimer = millis();
  }
}


const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM =
{
  CRGB::Red,
  CRGB::Gray,
  CRGB::Blue,
  CRGB::Black,

  CRGB::Red,
  CRGB::Gray,
  CRGB::Blue,
  CRGB::Black,

  CRGB::Red,
  CRGB::Red,
  CRGB::Gray,
  CRGB::Gray,
  CRGB::Blue,
  CRGB::Blue,
  CRGB::Black,
  CRGB::Black
};

RemoteController.ino

C/C++
/*
   Remote control program for drift cars
*/

#include <avr/wdt.h>

//Settings
#define MUSIC_OFF_ON_COMMAND 1
#define MUSIC_NEXT_COMMAND 2
#define ON_OFF_BACKLIGHT 3
#define NEXT_ILLUMINATION 4

//Steering wheel
#define CORNER_CORRECTION -11 //Correction of the central position of the wheels (- right, + left)
#define MIN_ANGLE 44 //Minimum steering angle
#define CENTER_ANGLE 90 CORNER_CORRECTION // Servo wheel center position + correction
#define MAX_ANGLE 124 //Max steering angle

#define WHEEL_MINIMUM_RESISTOR_VALUE 377 //Minimum variable resistor value
#define WHEEL_AVERAGE_RESISTOR_VALUE 509 //Average value of the variable resistor
#define WHEEL_MAXIMUM_RESISTOR_VALUE 623 //Maximum value of the variable resistor
#define WHEEL_DEADBAND 5 //Deadband


//Throttle lever
#define SPEED_AVERAGE_RESISTOR_VALUE 543 //Middle speed position
#define SPEED_MAXIMUM_RESISTOR_VALUE 632 // Maximum throttle position
#define SPEED_MINIMUM_RESISTOR_VALUE 470 //Minimum throttle position
#define SPEED_DEADBAND 5 //Deadband

//Battery overdischarge protection settings
#define OVER_DISCHARGE_VOLTAGE 3.1 //Battery over-discharge protection voltage
#define BOARD_SUPPLY_VOLTAGE 5.0 //Board supply voltage (needed to read the voltage)

//Pins
#define VARIABLE_RESISTOR_WHEEL A1
#define VARIABLE_RESISTOR_SPEED A0
#define VOLTMETER A2
#define MUSIC_BUTTON 2
#define LIGHT_BUTTON 3
#define LED_GREEN 4
#define LED_RED 5

int carSpeed;
int rotationAngle;
int rotationAngle2;

float volt = 0;

boolean overdischargeProtection = false;
boolean mb_flag = 0;
boolean mb_hold_flag = 0;
boolean lb_flag = 0;
boolean lb_hold_flag = 0;

unsigned long mb_last_press = 0;
unsigned long lb_last_press = 0;
unsigned long startTime = 0;

struct Str {
  uint8_t direction;
  int16_t speed;
  uint8_t angle;
  uint8_t command;
};
Str buf;


void setup() {
  Serial.begin(9600);

  pinMode(VARIABLE_RESISTOR_WHEEL, INPUT);
  pinMode(VARIABLE_RESISTOR_SPEED, INPUT);
  pinMode(VOLTMETER, INPUT);
  pinMode(MUSIC_BUTTON, INPUT_PULLUP);
  pinMode(LIGHT_BUTTON, INPUT_PULLUP);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_RED, OUTPUT);

  startTime = millis();

  digitalWrite(LED_GREEN, HIGH);
  wdt_enable(WDTO_1S);
}

void sendingData() {
  Serial.write((byte*)&buf, sizeof(buf)); //Sending data
  if (buf.command != 0) {
    buf.command = 0;
  }
  startTime = millis();
}


void resistorProcessing() {
  carSpeed = analogRead(VARIABLE_RESISTOR_WHEEL);
  rotationAngle = analogRead(VARIABLE_RESISTOR_SPEED);

  if (carSpeed > SPEED_MAXIMUM_RESISTOR_VALUE) {
    carSpeed = SPEED_MAXIMUM_RESISTOR_VALUE;
  }

  if (carSpeed < SPEED_MINIMUM_RESISTOR_VALUE) {
    carSpeed = SPEED_MINIMUM_RESISTOR_VALUE;
  }

  if ((rotationAngle < WHEEL_AVERAGE_RESISTOR_VALUE + WHEEL_DEADBAND) || (rotationAngle > WHEEL_AVERAGE_RESISTOR_VALUE - WHEEL_DEADBAND)) {
    buf.angle = CENTER_ANGLE;
  }

  if (rotationAngle > WHEEL_AVERAGE_RESISTOR_VALUE + WHEEL_DEADBAND) {
    buf.angle = map(rotationAngle, WHEEL_AVERAGE_RESISTOR_VALUE + WHEEL_DEADBAND, WHEEL_MAXIMUM_RESISTOR_VALUE, CENTER_ANGLE, MIN_ANGLE);
  }

  if (rotationAngle < WHEEL_AVERAGE_RESISTOR_VALUE - WHEEL_DEADBAND) {
    buf.angle = map(rotationAngle, WHEEL_AVERAGE_RESISTOR_VALUE - WHEEL_DEADBAND, WHEEL_MINIMUM_RESISTOR_VALUE, CENTER_ANGLE, MAX_ANGLE);
  }

  if ((carSpeed < SPEED_AVERAGE_RESISTOR_VALUE + SPEED_DEADBAND) || (carSpeed > SPEED_AVERAGE_RESISTOR_VALUE - SPEED_DEADBAND)) {
    buf.speed = 1500;
    buf.direction = 0;
  }

  if (carSpeed > SPEED_AVERAGE_RESISTOR_VALUE + SPEED_DEADBAND) {
    buf.speed = map(carSpeed, SPEED_AVERAGE_RESISTOR_VALUE + SPEED_DEADBAND, SPEED_MAXIMUM_RESISTOR_VALUE, 1500, 700);
    buf.direction = 1;
  }

  if (carSpeed < SPEED_AVERAGE_RESISTOR_VALUE - SPEED_DEADBAND) {
    buf.speed = map(carSpeed, SPEED_AVERAGE_RESISTOR_VALUE - SPEED_DEADBAND, SPEED_MINIMUM_RESISTOR_VALUE, 1500, 2200);
    buf.direction = 2;
  }
}


void buttons() {
  //Backlight change button
  if (digitalRead(LIGHT_BUTTON) == 0 && lb_flag == 0) {
    lb_flag = 1;
    lb_last_press = millis();
  }

  if (digitalRead(LIGHT_BUTTON) == 0 && lb_hold_flag == 0 && (millis() - lb_last_press) > 1000) {
    lb_hold_flag = 1;
    buf.command = ON_OFF_BACKLIGHT;

  }

  if (digitalRead(LIGHT_BUTTON) == 1 && lb_flag == 1) {
    if (lb_hold_flag == 0 && (millis() - lb_last_press) > 100) {
      buf.command = NEXT_ILLUMINATION;
    }

    lb_flag = 0;
    lb_hold_flag = 0;
  }


  //Button to change and turn on music
  if (digitalRead(MUSIC_BUTTON) == 0 && mb_flag == 0) {
    mb_flag = 1;
    mb_last_press = millis();
  }

  if (digitalRead(MUSIC_BUTTON) == 0 && mb_hold_flag == 0 && (millis() - mb_last_press) > 1000) {
    mb_hold_flag = 1;
    buf.command = MUSIC_OFF_ON_COMMAND;
  }

  if (digitalRead(MUSIC_BUTTON) == 1 && mb_flag == 1) {
    if (mb_hold_flag == 0 && (millis() - mb_last_press) > 80) {
      // 
      buf.command = MUSIC_NEXT_COMMAND;
    }

    mb_flag = 0;
    mb_hold_flag = 0;
  }
}

void loop() {
  volt = analogRead(VOLTMETER);
  if (((volt * BOARD_SUPPLY_VOLTAGE) / 1024) <= OVER_DISCHARGE_VOLTAGE) {
    overdischargeProtection = true;
    digitalWrite(LED_GREEN, LOW);
    digitalWrite(LED_RED, HIGH);
  }

  if (overdischargeProtection == false) {
    resistorProcessing();
    buttons();

    if ((millis() - startTime) > 50) {
      sendingData();
    }
  }
  wdt_reset();
}

Credits

YouRobotics

YouRobotics

1 project • 0 followers

Comments