// Maurice Ribble // 6-28-2009 // http://www.glacialwanderer.com/hobbyrobotics // This app just probes two external sensors (ADXL330 and IDG300) and // then sends that data over a serial connection. I used a sparkfun // breakout board to make using these chips easier. // http://www.sparkfun.com/commerce/product_info.php?products_id=741 // I wrote a processing.org app that reads in this data and graphs it // on a pc. #define X_ACCEL_APIN 0 #define Y_ACCEL_APIN 1 #define Z_ACCEL_APIN 2 //#define V_REF_APIN 3 //#define Y_RATE_APIN 4 //#define X_RATE_APIN 5 voidsetup() { Serial.begin(115200); } // If this is defined it prints out the FPS that we can send a // complete set of data over the serial port. //#define CHECK_FPS voidloop() { int xAccel=0, yAccel=0, zAccel=0; // , vRef=0, xRate=0, yRate=0; unsignedint startTag =0xDEAD; // Analog port maxes at 1023 so this is a safe termination value int loopCount; #ifdef CHECK_FPS unsignedlong startTime, endTime; startTime = millis(); #endif // Can't do more than 64 loops or could overflow the 16 bit ints // This just averages together as many sensor reads as we can in // order to reduce sensor noise. Might want to introduce add // a smarter filter her in the future. loopCount =12; // 12 gives a little over 100 FPS for(int i =0; i< loopCount; ++i) { // It takes 100 us (0.0001 s) to read an analog input xAccel += analogRead(X_ACCEL_APIN); yAccel += analogRead(Y_ACCEL_APIN); zAccel += analogRead(Z_ACCEL_APIN); //vRef += analogRead(V_REF_APIN); //xRate += analogRead(X_RATE_APIN); //yRate += analogRead(Y_RATE_APIN); } xAccel /= loopCount; yAccel /= loopCount; zAccel /= loopCount; //vRef /= loopCount; //xRate /= loopCount; //yRate /= loopCount; Serial.write( (unsigned byte*)&startTag, 2); Serial.write((unsigned byte*)&xAccel, 2); Serial.write((unsigned byte*)&yAccel, 2); Serial.write((unsigned byte*)&zAccel, 2); //Serial.write((unsigned byte*)&vRef, 2); //Serial.write((unsigned byte*)&xRate, 2); //Serial.write((unsigned byte*)&yRate, 2); #ifdef CHECK_FPS endTime = millis(); Serial.print(" - FPS: "); Serial.println(1.f/ (endTime-startTime) *1000); #endif }
// Maurice Ribble // 6-28-2009 // http://www.glacialwanderer.com/hobbyrobotics // This takes data off the serial port and graphs it. // There is an option to log this data to a file. // I wrote an arduino app that sends data in the format expected by this app. // The arduino app sends accelerometer and gyroscope data. import processing.serial.*; // Globals int g_winW =820; // Window Width int g_winH =600; // Window Height // boolean g_dumpToFile = true; // Dumps data to c:\\output.txt in a comma seperated format (easy to import into Excel) boolean g_enableFilter =true; // Enables simple filter to help smooth out data. cDataArray g_xAccel =new cDataArray(200); cDataArray g_yAccel =new cDataArray(200); cDataArray g_zAccel =new cDataArray(200); //cDataArray g_vRef = new cDataArray(200); //cDataArray g_xRate = new cDataArray(200); //cDataArray g_yRate = new cDataArray(200); cGraph g_graph =new cGraph(10, 190, 800, 400); Serial g_serial; PFont g_font; voidsetup() { size(820, 600, P2D); println(Serial.list()); g_serial =new Serial(this, Serial.list()[0], 115200, 'N', 8, 1.0); g_font = createFont("Arial",14,true); fill(0, 0, 0); } voiddraw() { // We need to read in all the avilable data so graphing doesn't lag behind while (g_serial.available() >=2*6+2) { processSerialData(); } strokeWeight(1); fill(255, 255, 255); g_graph.drawGraphBox(); strokeWeight(1.5); stroke(255, 0, 0); g_graph.drawLine(g_xAccel, 0, 1024); stroke(0, 255, 0); g_graph.drawLine(g_yAccel, 0, 1024); stroke(0, 0, 255); g_graph.drawLine(g_zAccel, 0, 1024); // add axis info // This draws the graph key info strokeWeight(1.5); stroke(255, 0, 0); line(20, 460, 40, 460); stroke(0, 255, 0); line(20, 480, 40, 480); stroke(0, 0, 255); line(20, 500, 40, 500); textFont(g_font,16); // STEP 3 Specify font to be used fill(0); // STEP 4 Specify font color text("xAccel", 60, 460); text("yAccel", 60, 480); text("zAccel", 60, 500); /* if (g_dumpToFile) { // This clears deletes the old file each time the app restarts byte[] tmpChars = {'\r', '\n'}; saveBytes("c:\\output.txt", tmpChars); } */ } // This reads in one set of the data from the serial port voidprocessSerialData() { int inByte =0; int curMatchPos =0; int[] intBuf =newint[2]; intBuf[0] =0xAD; intBuf[1] =0xDE; while (g_serial.available() <2); // Loop until we have enough bytes inByte = g_serial.read(); // This while look looks for two bytes sent by the client 0xDEAD // This allows us to resync the server and client if they ever // loose sync. In my testing I haven't seen them loose sync so // this could be removed if you need to, but it is a good way to // prevent catastrophic failure. while(curMatchPos <2) { if (inByte == intBuf[curMatchPos]) { ++curMatchPos; if (curMatchPos ==2) break; while (g_serial.available() <2); // Loop until we have enough bytes inByte = g_serial.read(); } else { if (curMatchPos ==0) { while (g_serial.available() <2); // Loop until we have enough bytes inByte = g_serial.read(); } else { curMatchPos =0; } } } while (g_serial.available() <2*3); // Loop until we have a full set of data // This reads in one set of data { byte[] inBuf =new byte[2]; int xAccel, yAccel, zAccel, vRef, xRate, yRate; g_serial.readBytes(inBuf); // Had to do some type conversion since Java doesn't support unsigned bytes xAccel = ((int)(inBuf[1]&0xFF) <<8) + ((int)(inBuf[0]&0xFF) <<0); g_serial.readBytes(inBuf); yAccel = ((int)(inBuf[1]&0xFF) <<8) + ((int)(inBuf[0]&0xFF) <<0); g_serial.readBytes(inBuf); zAccel = ((int)(inBuf[1]&0xFF) <<8) + ((int)(inBuf[0]&0xFF) <<0); g_serial.readBytes(inBuf); g_xAccel.addVal(xAccel); g_yAccel.addVal(yAccel); g_zAccel.addVal(zAccel); /* if (g_dumpToFile) // Dump data to a file if needed { String tempStr; tempStr = xAccel + "," + yAccel + "," + zAccel + "," + vRef + "," + xRate + "," + yRate + "\r\n"; FileWriter file; try { file = new FileWriter("c:\\output.txt", true); //bool tells to append file.write(tempStr, 0, tempStr.length()); //(string, start char, end char) file.close(); } catch(Exception e) { println("Error: Can't open file!"); } } *//* print(xAccel); print(" "); print(yAccel); print(" "); print(zAccel); print(" "); print(vRef); print(" "); print(xRate); print(" "); println(yRate); */ } } // This class helps mangage the arrays of data I need to keep around for graphing. classcDataArray { float[] m_data; int m_maxSize; int m_startIndex =0; int m_endIndex =0; int m_curSize; cDataArray(int maxSize) { m_maxSize = maxSize; m_data =newfloat[maxSize]; } void addVal(float val) { if (g_enableFilter && (m_curSize !=0)) { int indx; if (m_endIndex ==0) indx = m_maxSize-1; else indx = m_endIndex -1; m_data[m_endIndex] = getVal(indx)*.5+ val*.5; } else { m_data[m_endIndex] = val; } m_endIndex = (m_endIndex+1)%m_maxSize; if (m_curSize == m_maxSize) { m_startIndex = (m_startIndex+1)%m_maxSize; } else { m_curSize++; } } float getVal(int index) { return m_data[(m_startIndex+index)%m_maxSize]; } int getCurSize() { return m_curSize; } int getMaxSize() { return m_maxSize; } } // This class takes the data and helps graph it classcGraph { float m_gWidth, m_gHeight; float m_gLeft, m_gBottom, m_gRight, m_gTop; cGraph(float x, float y, float w, float h) { m_gWidth = w; m_gHeight = h; m_gLeft = x; m_gBottom = g_winH - y; m_gRight = x + w; m_gTop = g_winH - y - h; } void drawGraphBox() { stroke(0, 0, 0); rectMode(CORNERS); rect(m_gLeft, m_gBottom, m_gRight, m_gTop); } void drawLine(cDataArray data, float minRange, float maxRange) { float graphMultX = m_gWidth/data.getMaxSize(); float graphMultY = m_gHeight/(maxRange-minRange); for(int i=0; i<data.getCurSize()-1; ++i) { float x0 = i*graphMultX+m_gLeft; float y0 = m_gBottom-((data.getVal(i)-minRange)*graphMultY); float x1 = (i+1)*graphMultX+m_gLeft; float y1 = m_gBottom-((data.getVal(i+1)-minRange)*graphMultY); line(x0, y0, x1, y1); } } }