Stap 4: De auto - Monitoring en controle
Ik wilde voor het meten van de versnelling van de auto en ook de luchtdruk in de auto. Ik plaatste een Arduino Nano in de auto met druksensor en acceleratie sensor. Toevoeging van een Bluetooth-module toegestaan het car systeem te worden gelezen en bestuurd vanuit buiten de buis (via Blue Term Android app).
Aanvankelijk had ik de Bluetooth-module aangesloten via seriële Software. Hierdoor wilde schommelingen in het signaal aan op de fan controller pin, en we burn-out een paar elektronische snelheidscontrole. Met behulp van de standaard seriële pinnen 0 en 1 dit probleem uiteindelijk opgelost, maar nu vereist bij het laden van een bijgewerkte schets los te koppelen van het Bluetooth.
Lijst van gereedschappen en onderdelen
• Tools - see general tools list • Components o Arduino Nano V3 – Ebay $5 o 28 pin DIP Socket – Wide – (30 pin not available) Ebay $2 o Prototyping board – Ebay $3 o HC-06 Bluetooth Slave Module – Ebay $7 o BMP180 Barometric Sensor Module – Ebay $9 o MPU–6050 3 Axis Gyro/Accel Module – Banggood China $3
Dit is de schets van de Arduino gebruikt in de auto.
// HyperloopCar // Version 02 add accelerometer MPU6050 // Version 03 add ducted fan speed control (servo lib) // back off on SortwareSerial - just use pins 0 & 1 // Version 04 add gyro reading and roll calc for setting balancing servo // 04b go back to SoftwareSerial // 04c add timer to turn off fan after x seconds // Version 05 comment out balancing servo code, display pressure when it changes // 05b elim software serial since it caused interference on signal to ESC #include "Servo.h" //lib for running fan & servo #include "MPU6050.h" // accel/gyro sensor ///#include "SoftwareSerial.h" //for BT connection to other pins #include "SFE_BMP180.h" // temp.pressure sensor #include "Wire.h" // less than and greater than signs get lost in #include "I2Cdev.h" // the crude Instructables editor Servo esc; Servo servo; int throttle = 1300; // default. value to be set by BT serial input #define runtime 15000 // time until it shuts down automatically #define fanstop 700 // microsecond pulse with to stop fan long fanTime = 0; // how long fan has been on MPU6050 accelgyro; //0x68 is default I2C address //tie AD0 pin to 5v+ to set 0x69 // for Roll calculation #define M_PI 3.14159265359 #define dt 0.01 #define gyroSens 65.536 //copied from web example ??? seems to work int16_t ax, ay, az; int16_t gx, gy, gz; int16_t ayMaxPlus, ayMaxMinus, axMax, azMax; //save max values //#define OUTPUT_READABLE_ACCELGYRO #define cvtFtSec2 62 //conversion from raw to ft/sec sq #define OUTPUT_BINARY_ACCELGYRO float roll = 0; //SoftwareSerial mySerial(5, 6); // RX, TX Objst for BT serial int ledPin = 2; char state = 0; int flag = 0; char stat; // variables for temp/pressure double T,P,p0,a; float psi; float temp = 0; float savePressure; char ctlChar = '0'; SFE_BMP180 pressure; //object for temp/pressure sensor #define ALTITUDE 137.0 // Est Altitude in meters int pressureCtr = 0; // BMP-180 Wiring //Any Arduino pins labeled: SDA SCL 5+ Gnd //Uno, Redboard, Pro: A4 A5 //Mega2560, Due: 20 21 //Leonardo: 2 3 int serialCtr = 0; //don't look for serial i/p every time thru loop void setup() { esc.attach(9, fanstop, 2000); // pin for electronic speed control // for ducted fan, min microsec pulse with, and max to set range esc.writeMicroseconds(fanstop); //set to off // servo.attach(10); // pin for balancing servo Wire.begin(); //needed? pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); Serial.begin(9600); // Default connection rate for my BT module Serial.println("HyperloopCar05b"); if (!pressure.begin()) { Serial.println("BMP180 init fail\n\n"); while(1); // Pause forever. } Serial.println("got to here"); accelgyro.initialize(); accelgyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_16); //change from default 2g range // verify connection Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed"); Serial.print("0->9 = max fan"); Serial.print(" s=fan start o=fan off"); Serial.println(" p=print readings i=initialize ESC"); pinMode(13, OUTPUT); digitalWrite(13, HIGH); // all's well indicator } void loop() { serialCtr++; if (serialCtr > 10) {; //check for user input occasionally checkInput(); serialCtr = 0; } if ((fanTime != 0) && (millis() - fanTime > runtime)) { stopFan(); // turn it off automatically } // get info rom MPU6050, acceleration & gyro accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); //get readings from MPU6050 if (ay > 0 && ay > ayMaxPlus) ayMaxPlus = ay; //save fwd/bkwd accel raw value if (ay < 0 && ay < ayMaxMinus) ayMaxMinus = ay; /* calcRoll(ax, ay, az, gy, &roll); // calc roll. pass a & g values and ptr to roll int degRoll = roll * 100; // Serial.print("degRoll=");Serial.println(degRoll); //delay(100); int servoangle = map(degRoll, -50, 50, 60, 135); //map +-50deg angle to servo maxes // adj mapping to tune balance if (abs(degRoll < 50)) { // Serial.print("angle=");Serial.println(servoangle); servo.write(servoangle); // move trim servo to keep balance } */ pressureCtr++; if (pressureCtr > 100) { //only do this every once in a while pressureCtr = 0; checkPressure(); //get current psi & temp // Serial.print("savePressure=");Serial.print(savePressure); // Serial.print(" psi=");Serial.println(psi); if (abs(savePressure - psi) > .5) { savePressure = psi; dispReadings(); } } } int ms; void startFan() { //increase speed gradually to max fanTime = millis(); //save the time when we turn it on Serial.print(" Up to "); Serial.print(throttle); Serial.print(" max for "); Serial.print(runtime / 1000);Serial.println(" seconds"); for (ms=fanstop; ms <= throttle; ms+=12) { // Serial.print(" pulse ms="); // Serial.println(ms); esc.writeMicroseconds(ms); delay(125); } } void stopFan() { Serial.println("Stopping the fan"); for (ms=ms-100; ms >= fanstop; ms-=25) { // Serial.print(" pulse ms="); // Serial.println(ms); esc.writeMicroseconds(ms); delay(125); } fanTime = 0; } void checkInput() { if (Serial.available() > 0){ // see if any user input ctlChar = Serial.read(); Serial.println(); int i = ctlChar - '0'; //convert singe char to integer if (i >= 0 && i <= 9) { //set throttle throttle = map(i, 0, 9, 1300, 1800); //vary bewteen low & high Serial.print(" max throttle pulse set to "); Serial.println(throttle); } else if (ctlChar == 's') { startFan(); } else if (ctlChar == 'o') { stopFan(); } else if (ctlChar == 'p') { dispReadings(); } else if (ctlChar == 'i') { initializeESC(); } } } /* void calcRoll(int16_t aax, int16_t aay, int16_t aaz, int16_t ggy, float *roll) { float rollAcc; // integrate gyro data , cvt angular speed to angle *roll -= ((float)ggy / gyroSens) * dt; // angle // compensate for drift wil accel data if valid int forceMagnitudeApprox = abs(aax) + abs(aay) + abs(aaz); if (forceMagnitudeApprox > 8192 * forceMagnitudeApprox < 32768) { // turning around the x & z axes results in vector on the y axis rollAcc = atan2((float)aax, (float)aaz) * 180 / M_PI; *roll = *roll * 0.98 + rollAcc * 0.02; // smooth it in } } */ void initializeESC() { // "train" esc to recognize arduino throttle // long savTime = millis(); esc.writeMicroseconds(2000); //set to max Serial.println("Now sending max power to ESC"); Serial.println("Turn on power to ESC, wait 2 sec, and hit any key when ready"); while (!Serial.available()); // wait for input Serial.read(); // delay(2000); // for >2 seconds esc.writeMicroseconds(fanstop); //set to min Serial.print("..."); delay(2000); Serial.println("done"); } void dispReadings() { // diplay readings on Serial device Serial.print(" ayMax="); Serial.print(ayMaxPlus / cvtFtSec2); Serial.print(" "); // temp & pressure Serial.print(temp); Serial.print("F "); Serial.print(psi,1); Serial.println(" psi"); } void checkPressure() { stat = pressure.startTemperature(); if (stat != 0) { delay(stat); // Wait for the measurement to complete: // Retrieve the completed temperature measurement: // Note that the measurement is stored in the variable T. // Function returns 1 if successful, 0 if failure. stat = pressure.getTemperature(T); // Retrieve the completed temp if (stat != 0) { // Start a pressure measurement: // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait). // If request is successful, the number of ms to wait is returned. // If request is unsuccessful, 0 is returned. stat = pressure.startPressure(3); if (stat != 0) { // Wait for the measurement to complete: delay(stat); temp = T; //Farenheit it turns out // temp = (((9.0/5.0)*T)+32.0); //needed for Farenheit // Retrieve the completed pressure measurement: // Note that the measurement is stored in the variable P. // Note also that the function requires the previous temperature measurement (T). // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.) // Function returns 1 if successful, 0 if failure. stat = pressure.getPressure(P,T); if (stat != 0) { psi = P*0.014503773773; } else Serial.println("error retrieving pressure measurement\n"); } else Serial.println("error starting pressure measurement\n"); } else Serial.println("error retrieving temperature measurement\n"); } else Serial.println("error starting temperature measurement\n"); // delay(2000); }