diff --git a/apps.json b/apps.json index 3694da40d..d9db4dfe4 100644 --- a/apps.json +++ b/apps.json @@ -2047,6 +2047,20 @@ {"name":"widancs.settings.js","url":"settings.js"} ] }, + { "id": "accelrec", + "name": "Acceleration Recorder", + "shortName":"Accel Rec", + "icon": "app.png", + "version":"0.01", + "interface": "interface.html", + "description": "This app puts the Bangle's accelerometer into 100Hz mode and reads 2 seconds worth of data after movement starts. The data can then be exported back to the PC.", + "tags": "", + "readme": "README.md", + "storage": [ + {"name":"accelrec.app.js","url":"app.js"}, + {"name":"accelrec.img","url":"app-icon.js","evaluate":true} + ] + }, { "id": "cprassist", "name":"CPR Assist", diff --git a/apps/accelrec/ChangeLog b/apps/accelrec/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/accelrec/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/accelrec/README.md b/apps/accelrec/README.md new file mode 100644 index 000000000..40d981b6a --- /dev/null +++ b/apps/accelrec/README.md @@ -0,0 +1,30 @@ +# Acceleration Recorder + +This app records a short period of acceleration data from the accelerometer +and + +## Usage + +* Start the `Accel Rec` App +* Select `Start` and place the Bangle with its rear face pointing downwards (screen up) +* After the counter counts down, it will display `Waiting` +* Now move the Bangle upwards (in the direction of `N`) + +At this point the 2 second recording will start at 100 samples per second, +with a maximum of 8g. + +After the 2 seconds you'll see a graph with calculated maximum acceleration +and velocity. + +* Press BTN2 (labelled `FINISH`) +* Not choose `Save` and choose a slot, from 1 to 6. Slots already used +are marked with a `*` + +## Getting data + +* Go to the App Loader: https://banglejs.com/apps/ +* Click `Connect` up the Top Right +* Click `My Apps` +* Click the Downward pointing arrow next to `Acceleration Recorder` +* After it loads, you'll see the recorded Acceleration values +* You can now either save them to a CSV file, or delete them diff --git a/apps/accelrec/app-icon.js b/apps/accelrec/app-icon.js new file mode 100644 index 000000000..2ed8bee20 --- /dev/null +++ b/apps/accelrec/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AC1rAAQrrF9QuHF8tBoIvsFwIwIF04wHF1AwGF1IwFF1QwDF0llGBAuki0QiwvnFwoABGAqMlFwQABSQbqmL44umX44uoSQS7oGRAukRAouqdAoubiwAFnaMDFwQABXbk6FxRfJF0y/HF1CSCdTwuOdTpjGF1gACF11rtYuKnYvhsowKncWF8K+BGBAuBF8IiBGBAuCF8YwHFwYvf4XCz06GAwuEF7283nB4IwEegJoDF8G74XO5owBEoo2CF8PI53O4O8ZJIufF4PI4QEBF5LteFQIADBo6QBFzwvDBxc6F74A/AH4A/AFQ")) diff --git a/apps/accelrec/app.js b/apps/accelrec/app.js new file mode 100644 index 000000000..5fb91e2e4 --- /dev/null +++ b/apps/accelrec/app.js @@ -0,0 +1,169 @@ +var acc; +var HZ = 100; +var SAMPLES = 2*HZ; // 2 seconds +var SCALE = 5000; +var THRESH = 1.01; +var accelx = new Int16Array(SAMPLES); +var accely = new Int16Array(SAMPLES); // North +var accelz = new Int16Array(SAMPLES); // Into clock face +var accelIdx = 0; +var lastAccel = undefined; +function accelHandlerTrigger(a) {"ram" + if (a.mag*2>THRESH) { // *2 because 8g mode + tStart = getTime(); + g.drawString("Recording",g.getWidth()/2,g.getHeight()/2,1); + Bangle.removeListener('accel',accelHandlerTrigger); + Bangle.on('accel',accelHandlerRecord); + if (lastAccel) accelHandlerRecord(lastAccel); + accelHandlerRecord(a); + } + lastAccel = a; +} +function accelHandlerRecord(a) {"ram" + var i = accelIdx++; + accelx[i] = a.x*SCALE*2; + accely[i] = -a.y*SCALE*2; + accelz[i] = a.z*SCALE*2; + if (accelIdx>=SAMPLES) recordStop(); +} +function recordStart() {"ram" + Bangle.setLCDTimeout(0); // force LCD on + accelIdx = 0; + lastAccel = undefined; + Bangle.accelWr(0x1B,0x03 | 0x40); // 100hz output, ODR/2 filter + Bangle.accelWr(0x18,0b11110100); // +-8g + Bangle.setPollInterval(10); // 100hz input + setTimeout(function() { + Bangle.on('accel',accelHandlerTrigger); + g.clear(1).setFont("6x8",2).setFontAlign(0,0); + g.drawString("Waiting",g.getWidth()/2,g.getHeight()/2); + }, 200); +} + + +function recordStop() {"ram" + console.log("Length:",getTime()-tStart); + Bangle.setPollInterval(80); // default poll interval + Bangle.accelWr(0x1B,0x0); // default 12.5hz output + Bangle.accelWr(0x18,0b11101100); // +-4g + Bangle.removeListener('accel',accelHandlerRecord); + E.showMessage("Finished"); + showData(); +} + + +function showData() { + g.clear(1); + var w = g.getWidth()-20; // width + var m = g.getHeight()/2; // middle + var s = 12; // how many pixels per G + g.fillRect(9,0,9,g.getHeight()); + g.setFontAlign(0,0); + for (var l=-8;l<=8;l++) + g.drawString(l, 5, m - l*s); + + function plot(a) { + g.moveTo(10,m - a[0]*s/SCALE); + for (var i=0;imaxAccel) maxAccel=a; + vel += a/HZ; + if (vel>maxVel) maxVel=vel; + } + g.reset(); + g.setFont("6x8").setFontAlign(1,0); + g.drawString("Max Y Accel: "+maxAccel.toFixed(2)+" g",g.getWidth()-14,g.getHeight()-50); + g.drawString("Max Y Vel: "+maxVel.toFixed(2)+" m/s",g.getWidth()-14,g.getHeight()-40); + //console.log("End Velocity "+vel); + g.setFont("6x8").setFontAlign(0,0,1); + g.drawString("FINISH",g.getWidth()-4,g.getHeight()/2); + setWatch(function() { + showMenu(); + }, BTN2); +} + +function showBig(txt) { + g.clear(1); + g.setFontVector(80).setFontAlign(0,0); + g.drawString(txt,g.getWidth()/2, g.getHeight()/2); + g.flip(); +} + +function countDown() { + showBig(3); + setTimeout(function() { + showBig(2); + setTimeout(function() { + showBig(1); + setTimeout(function() { + recordStart(); + }, 800); + }, 1000); + }, 1000); +} + +function showMenu() { + Bangle.setLCDTimeout(10); // set timeout for LCD in menu + var menu = { + "" : { title : "Acceleration Rec" }, + "Start" : function() { + E.showMenu(); + if (accelIdx==0) countDown(); + else E.showPrompt("Overwrite Recording?").then(ok=>{ + if (ok) countDown(); else showMenu(); + }); + }, + "Plot" : function() { + E.showMenu(); + if (accelIdx) showData(); + else E.showAlert("No Data").then(()=>{ + showMenu(); + }); + }, + "Save" : function() { + E.showMenu(); + if (accelIdx) showSaveMenu(); + else E.showAlert("No Data").then(()=>{ + showMenu(); + }); + }, + "Exit" : function() { + load(); + }, + }; + E.showMenu(menu); +} + +function showSaveMenu() { + var menu = { + "" : { title : "Save" } + }; + [1,2,3,4,5,6].forEach(i=>{ + var fn = "accelrec."+i+".csv"; + var exists = require("Storage").read(fn)!==undefined; + menu["Recording "+i+(exists?" *":"")] = function() { + var csv = ""; + for (var i=0;i + + + + +
+ + + + +