Paso 4: El auto - monitoreo y Control
Quería medir la aceleración del coche y también la presión de aire en el coche. Coloqué un Arduino Nano en el coche con el sensor de aceleración y sensor de presión. Además de un módulo de Bluetooth permiten el sistema de lectura y controlados desde fuera del tubo (a través de app Android azul de término).
Inicialmente tuve el módulo Bluetooth conectado a través de serie de Software. Esto causó fluctuaciones salvajes en la señal enviada con el conector de regulador de ventilador, y quema un par de controles de velocidad electrónicos. Usando los pines Serial estándar 0 y 1 finalmente solucionó este problema, pero ahora requiere desconectar el Bluetooth cuando se carga un esbozo actualizado.
Lista de herramientas y componentes
• 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
Este es el sketch de Arduino en el coche.
// 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); }