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.