Introduction: Drag Reduction System

This instructable was created in fulfillment of the project requirement of the Makecourse at the University of South Florida (www.makecourse.com).

The Idea for this project was inspired by my involvement with the Formula Society of Automotive Engineers at USF.

Basically, a Drag Reduction System (DRS) is generally used on formula style cars during high speeds when the need for downforce is overtaken by speed. This is typically done by adjusting the orientation of the main element in the aerodynamics package to allow air to pass through.

For this project I have attempted to model a basic DRS system using 3-D printed parts and an Arduino.

Step 1: Design

Solidworks was used to design the parts for this project. Several redesigns of the chassis and wheels were needed to better accommodate the 3-D printers. The chassis ended up being to large to fit in the printer so I had to print out sections of it and glue them together.

I wanted an easy way to mount the motors in the rear of the car so I very carefully measured the motors and made sure to design the chassis with the proper clearances for the motors.

I also wanted a way to access the motors easily for serviceability purposes. This was achieved by designing a cover with four hood pins. It took some sanding to get the hood to slide on and off easily but its much quicker and less frustrating when dealing with accurate designs and a 3-D Printer than measuring and drilling... and measuring and drilling again.

Time well spent in the design process can save lots of frustration when assembling the final product.

Step 2: 3-D Print Parts

This project was almost entirely made from 3-D printed parts. Each part plays an important role in the functionality of the system.

The wing is mounted to the hood using an 1/8" steel or aluminum rod. The hood is mounted to the chassis via the four 1/4" holes on the corners where the hood pins stick out.

Step 3: Build Your Control System

Here is a fritzing diagram showing how to connect everything to the Arduino. The Arduino is connected to each component through various inputs and outputs. The LCD display, servo, and motors are powered via the relay normally closed contact. When the Arduino receives the correct IR command the relay will turn on and provide power to these components.

The motors speed is controlled by the potentiometer through an analog input on the Arduino. When the motor reaches a certain rpm the servo will move the wing down and the green light will come on.

Step 4: Compose an Arduino Sketch

Below is the code that I used to control my system.

I am using several libraries to enable the use of the IR receiver, LCD display over I2C, and the servo.

Most of my variables are defined within the functions that use them but we need to define the receive pin for the IR reciever so that we can instantiate the IR receiver object. We also need to instantiate the results of the IR receiver and the servo and LCD display.

The setup function begins by starting the serial monitor and initializing the LCD and turning on the backlight. During the setup we also need to start the IR receiver attach the servo to pin number 9 and define pins 6 and 7 as outputs for the motor and relay.

The main loop just calls three functions which are described below

/***************************************************************************************
Control System Program for a simple Arduino based Drag Reduction System 
By Korey Prince


This program turns a relay on and off using an IR remote and detects the speed of a 
motor to determine when to actuate a wing based on the input of a potentiometer
***************************************************************************************/
//include all libraries used in this program 
#include <irremote.h>
#include <liquidcrystal_i2c.h>
#include <wire.h> 
#include <servo.h>
 
int RECV_PIN = 11;//define IR recieve as pin 11
IRrecv irrecv(RECV_PIN);//instantiate a IR receiver object
decode_results results;//instantiate a decode_results object. 
			//This object is separate from the IR receiver.

Servo myservo;//instantiate a servo object to control the wing

LiquidCrystal_I2C lcd(0x27,16,2);//instantiate a 16x2 I2C LCD display with address 0x27
void setup()
{
  Serial.begin(9600);//Start the serial monitor
  lcd.init();// initialize the lcd 
  
  irrecv.enableIRIn(); // Start the receiver
  
  myservo.attach(9, 544, 1200);// attaches the servo on pin 9 to the servo object

  pinMode(6, OUTPUT);//define pin 6 as an output for the motor  
  pinMode(7, OUTPUT);//define pin 7 as an output for the relay
  pinMode(8, OUTPUT);//define pin 8 as an output for the green LED
  pinMode(12, OUTPUT);//define pin 12 as an output for the red LED  
}
void loop()
{   
  //get commands from the recvIR function to turn power on with remote control
  recvIR();
 
  //check the speed of the motors and activate the servo if above threshold
  activateDRS();

  //get the revolutions per milli-second from revPerMilli function
  revPerMilli();
}

The idea of the activateDRS function is to turn a servo to a specific position when a condition is met. The condition in this case is the motorSpeed. If the motor speed is greater than of equal to 200 the servo will move to the 60 deg position. If the servo is less that 200 that the servo will return to the original position.

int activateDRS(){<br>      int pos = 0;//define the pos variable for the position 
					//of the servo
      int motorSpeed;//define another variable and set it equal to the function 
			//motorController()

      motorSpeed = motorController();
      
    //move the servo to its active location when the speed of the motors reaches 200
    if(motorSpeed >= 200){
      for(pos = 60; pos>=0; pos-=1) // goes from 0 degrees to 60 degrees 
      {                             // in steps of 1 degree 
        myservo.write(pos);// tell servo to go to position in variable 'pos' 
        digitalWrite(8, HIGH);
        digitalWrite(12, LOW);
        delay(15);// waits 15ms for the servo to reach the position
        lcd.setCursor(0,1);
        lcd.print("DRS: ON ");
        break;// allow the program to exit after the servo position is reached
      }
      //tell the user that the DRS system is ON
      Serial.println("DRS: ON");      
    }
    if(motorSpeed < 200){
      for(pos = 0; pos <= 60; pos += 1)// goes from 900 degrees to 0 degrees 
      {                                
        myservo.write(pos);// tell servo to go to position in variable 'pos' 
        digitalWrite(8, LOW);
        digitalWrite(12, HIGH);
        delay(15);// waits 15ms for the servo to reach the position
        lcd.setCursor(0,1);
        lcd.print("DRS: OFF");
        break;// allow the program to exit after the servo position is reached
      }
    }
    return motorSpeed;
}

The motor controller function simply defines a potentiometer as an analog input and maps the motor value to the digital range that is used in the activateDRS function

int motorController(){<br>  //define variables 
  int potPin = A0;
  int motorPin = 6;
  int potValue = 0;
  int motorValue = 0;
  
  //define the potPin as an analog input
  potValue = analogRead(potPin);  
  
  //map the analog value of the pot pin to the motor
  motorValue = map(potValue, 0, 1023, 0, 255);
  //write the analog value of the motor to the PWM motor pin 6
  analogWrite(motorPin, motorValue); 
  Serial.println(motorValue);
  
return motorValue;
}

Here we check to see if a specific command has been received. if it has the we turn the relay on. if a different command is sent the relay will turn off which cuts power to the motor and servo.

void recvIR(){<br>    //has a transmission been received?
    if (irrecv.decode(&results)) 
    {
      //Serial.println(results.value);//If yes: interpret the received commands...
      if (results.value == 12419199){//Power buttom on AOC remote
        lcd.clear();
        lcd.noBacklight();//turn on the backlight
        delay(100);             
      }
      if (results.value == 12398799){//Vol up buttom on AOC remote
        delay(100);
        lcd.clear();
        lcd.backlight();//turn on the backlight
        lcd.print("System Ready");
        digitalWrite(7, HIGH);   // turn the Relay on (HIGH is the voltage level)
        delay(100);              
      }
      if (results.value == 12392679){//Channel UP buttom on AOC remote
        lcd.clear();
        lcd.print("System OFF");
        delay(500);
        lcd.noBacklight();//turn off the backlight
        digitalWrite(7, LOW);    // turn the Relay off by making the voltage LOW
        digitalWrite(12, LOW);
        delay(100);              
      }
    irrecv.resume(); // Receive the next value
  }
}

The revsPerMilli function calculates the revolutions of the wheel per millisecond by first waiting for the interrupt value to increment to above 100. Once the revolutions reach 100 the circumference and speed of the wheel are calculated. this function uses a built in Arduino function called millis to get the time in milliseconds.

Note: I have not been able to get the encoders to work properly so this function is not necessary for the code to work. I mainly added it as an improvement for later.

float revPerMilli(){<br>  //define variables
  unsigned int rpmilli;
  float speed;
  unsigned long timeold;
  //calculate the revolutions per milli(second)
  rpmilli = revolutions/(millis()-timeold);
  
if (revolutions >= 100) { 
    //Update RPM every 100 counts, increase this for better RPM resolution,
    //decrease for faster update
    delay(100);
    
    //store the previous time in a variable    
    timeold = millis();
    revolutions = 0;
    
    //calculate the circumference of the wheel
    float WHEELCIRC = 2 * PI * 0.065;
    //define the speed of the wheel
    speed = rpmilli * WHEELCIRC * 3600;
    
    Serial.print("RPM:  ");
    Serial.print(rpmilli);
    delay(100);
    }
    return rpmilli;
}

Step 5: Assemble

Now all you have to do is put everything together. Make sure that everything works properly before installing it permanently. Its always a good idea to "breadboard" your electrical design to make sure everything works with eachother and to see if there is anything that needs to be changed.