diff --git a/tabs/motor_outputs.css b/tabs/motor_outputs.css
index df065c97..70099528 100644
--- a/tabs/motor_outputs.css
+++ b/tabs/motor_outputs.css
@@ -1,97 +1,183 @@
-.tab-motor_outputs {
+.tab-motor_outputs .plot_control {
+ float: right;
+
+ width: 158px;
+
+ border: 1px solid silver;
}
- .tab-motor_outputs .left.motors {
+ .tab-motor_outputs .plot_control .title {
+ line-height: 20px;
+ font-weight: bold;
+ text-align: center;
+
+ border-bottom: 1px solid silver;
+ background-color: #ececec;
+ }
+ .tab-motor_outputs .plot_control dl {
+ padding: 5px 0 0 5px;
+ line-height: 22px;
+ }
+ .tab-motor_outputs .plot_control dt {
float: left;
+ width: 60px;
+ height: 22px;
+
+ font-weight: bold;
+ }
+ .tab-motor_outputs .plot_control dd {
+ margin-left: 20px;
+ height: 22px;
+ }
+ .tab-motor_outputs .plot_control .x {
+ color: #00A8F0;
+ }
+ .tab-motor_outputs .plot_control .y {
+ color: #C0D800;
+ }
+ .tab-motor_outputs .plot_control .z {
+ color: #CB4B4B;
+ }
+.tab-motor_outputs select {
+ width: 70px;
+ border: 1px solid silver;
+}
+.tab-motor_outputs svg {
+ float: left;
+
+ width: calc(100% - 168px); /* - (plot control, margin)*/
+ height: 140px;
+
+ margin-bottom: 10px;
+}
+.tab-motor_outputs .grid .tick {
+ stroke: silver;
+ stroke-width: 1px;
+ shape-rendering: crispEdges;
+}
+.tab-motor_outputs .grid path {
+ stroke-width: 0;
+}
+.tab-motor_outputs .data .line {
+ stroke-width: 2px;
+ fill: none;
+}
+.tab-motor_outputs .axis path, .tab-motor_outputs .axis line {
+ fill: none;
+ stroke: #000000;
+ stroke-width: 1px;
+ shape-rendering: crispEdges;
+}
+.tab-motor_outputs .line:nth-child(1) {
+ stroke: #00A8F0;
+}
+.tab-motor_outputs .line:nth-child(2) {
+ stroke: #C0D800;
+}
+.tab-motor_outputs .line:nth-child(3) {
+ stroke: #CB4B4B;
+}
+
+.tab-motor_outputs .left.motors {
+ float: left;
+
+ margin-right: 50px;
+
+ width: calc(50% - 50px);
+}
+.tab-motor_outputs .right.servos {
+ float: left;
+
+ width: 50%;
+}
+.tab-motor_outputs .titles {
+ height: 20px;
+}
+ .tab-motor_outputs .titles li {
+ float: left;
+
+ width: calc((100% / 9) - 10px);
+ margin-right: 10px;
+
+ text-align: center;
+ }
+ .tab-motor_outputs .servos .titles li {
+ float: right;
+
+ width: calc((100% / 8) - 10px);
+
+ margin: 0 0 0 10px;
+ }
+ .tab-motor_outputs .titles .active {
+ color: green;
+ }
+.tab-motor_outputs .m-block {
+ float: left;
+
+ width: calc((100% / 9) - 12px);
+ height: 80px;
+
+ margin-right: 10px;
+
+ border: 1px solid silver;
+ background-color: #e9e9e9;
+}
+.tab-motor_outputs .servos .m-block {
+ float: right;
+
+ width: calc((100% / 8) - 12px);
+
+ margin: 0 0 0 10px;
+}
+.tab-motor_outputs .indicator {
+ float: left;
+
+ width: 100%;
+}
+.tab-motor_outputs p {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 5px;
+
+ border: 1px dotted silver;
+}
+.tab-motor_outputs .motor_testing {
+ display: none;
+}
+ .tab-motor_outputs .motor_testing .left {
margin-right: 50px;
width: calc(50% - 50px);
}
- .tab-motor_outputs .right.servos {
- float: left;
+ .tab-motor_outputs .motor_testing .sliders {
+ }
+ .tab-motor_outputs .motor_testing .sliders input {
+ -webkit-appearance: slider-vertical;
- width: 50%;
+ width: calc((100% / 9) - 3px); /* - (width / 9 elements, not sure about -3 */
+ height: 80px;
+ }
+ .tab-motor_outputs .motor_testing .values {
+ margin-top: 5px;
}
- .tab-motor_outputs .titles {
- height: 20px;
- }
- .tab-motor_outputs .titles li {
+ .tab-motor_outputs .motor_testing .values li {
float: left;
- width: calc((100% / 9) - 10px); /* - (margin) */
- margin-right: 10px;
+ width: calc((100% / 9));
text-align: center;
}
- .tab-motor_outputs .servos .titles li {
- width: calc((100% / 8) - 10px); /* - (margin) */
- }
- .tab-motor_outputs .titles .active {
- color: green;
- }
- .tab-motor_outputs .m-block {
- float: left;
+ .tab-motor_outputs .motor_testing .notice {
+ float: right;
- width: calc((100% / 9) - 12px); /* - (margin, border) */
- height: 160px;
+ width: calc(50% - 22px);
- margin-right: 10px;
-
- border: 1px solid silver;
- background-color: #e9e9e9;
- }
- .tab-motor_outputs .servos .m-block {
- width: calc((100% / 8) - 12px); /* - (margin, border) */
- }
- .tab-motor_outputs .indicator {
- float: left;
-
- width: 100%;
- }
- .tab-motor_outputs p {
- margin-top: 20px;
padding: 5px;
border: 1px dotted silver;
}
- .tab-motor_outputs .motor_testing {
- display: none;
- }
- .tab-motor_outputs .motor_testing .left {
- margin-right: 50px;
+ .tab-motor_outputs .motor_testing .notice input[type="checkbox"] {
+ margin-left: 5px;
- width: calc(50% - 50px);
- }
- .tab-motor_outputs .motor_testing .sliders {
- margin-top: 20px;
- }
- .tab-motor_outputs .motor_testing .sliders input {
- -webkit-appearance: slider-vertical;
-
- width: calc((100% / 9) - 3px); /* - (width / 9 elements, not sure about -3 */
- }
- .tab-motor_outputs .motor_testing .values {
- margin-top: 5px;
- }
- .tab-motor_outputs .motor_testing .values li {
- float: left;
-
- width: calc((100% / 9));
-
- text-align: center;
- }
- .tab-motor_outputs .motor_testing .notice {
- float: left;
-
- width: calc(50% - 12px); /* - (padding, border) */
-
- margin-top: 20px;
- padding: 5px;
-
- border: 1px dotted silver;
- }
- .tab-motor_outputs .motor_testing .notice input[type="checkbox"] {
- margin-left: 5px;
-
- vertical-align: middle;
- }
\ No newline at end of file
+ vertical-align: middle;
+ }
\ No newline at end of file
diff --git a/tabs/motor_outputs.html b/tabs/motor_outputs.html
index f6e1e70d..72e0853e 100644
--- a/tabs/motor_outputs.html
+++ b/tabs/motor_outputs.html
@@ -1,4 +1,44 @@
+
+
+
Accelerometer - g
+
+
+ -
+
+
+
+ -
+
+
+ - X:
- 0
+ - Y:
- 0
+ - Z:
- 0
+
+
+
+
+
- M - 1
@@ -23,24 +63,24 @@
- - S - 1
- - S - 2
- - S - 3
- - S - 4
- - S - 5
- - S - 6
- - S - 7
- S - 8
+ - S - 7
+ - S - 6
+ - S - 5
+ - S - 4
+ - S - 3
+ - S - 2
+ - S - 1
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/tabs/motor_outputs.js b/tabs/motor_outputs.js
index 0e5ace66..c3bf1058 100644
--- a/tabs/motor_outputs.js
+++ b/tabs/motor_outputs.js
@@ -2,6 +2,124 @@ function tab_initialize_motor_outputs() {
ga_tracker.sendAppView('Motor Outputs Page');
GUI.active_tab = 'motor_outputs';
+ function initSensorData() {
+ for (var i = 0; i < 3; i++) {
+ SENSOR_DATA.accelerometer[i] = 0;
+ }
+ }
+
+ function initDataArray(length) {
+ var data = new Array(length);
+ for (var i = 0; i < length; i++) {
+ data[i] = new Array();
+ data[i].min = -1;
+ data[i].max = 1;
+ }
+ return data;
+ }
+
+ function addSampleToData(data, sampleNumber, sensorData) {
+ for (var i = 0; i < data.length; i++) {
+ var dataPoint = sensorData[i];
+ data[i].push([sampleNumber, dataPoint]);
+ if (dataPoint < data[i].min) {
+ data[i].min = dataPoint;
+ }
+ if (dataPoint > data[i].max) {
+ data[i].max = dataPoint;
+ }
+ }
+ while (data[0].length > 300) {
+ for (i = 0; i < data.length; i++) {
+ data[i].shift();
+ }
+ }
+ return sampleNumber + 1;
+ }
+
+ var margin = {top: 20, right: 10, bottom: 10, left: 20};
+ function updateGraphHelperSize(helpers) {
+ helpers.width = helpers.targetElement.width() - margin.left - margin.right;
+ helpers.height = helpers.targetElement.height() - margin.top - margin.bottom;
+
+ helpers.widthScale.range([0, helpers.width]);
+ helpers.heightScale.range([helpers.height, 0]);
+
+ helpers.xGrid.tickSize(-helpers.height, 0, 0);
+ helpers.yGrid.tickSize(-helpers.width, 0, 0);
+ }
+
+ function initGraphHelpers(selector, sampleNumber, heightDomain) {
+ var helpers = {selector: selector, targetElement: $(selector), dynamicHeightDomain: !heightDomain};
+
+ helpers.widthScale = d3.scale.linear()
+ .clamp(true)
+ .domain([(sampleNumber - 299), sampleNumber]);
+
+ helpers.heightScale = d3.scale.linear()
+ .clamp(true)
+ .domain(heightDomain || [1, -1]);
+
+ helpers.xGrid = d3.svg.axis();
+ helpers.yGrid = d3.svg.axis();
+
+ updateGraphHelperSize(helpers);
+
+ helpers.xGrid
+ .scale(helpers.widthScale)
+ .orient("bottom")
+ .ticks(5)
+ .tickFormat("");
+
+ helpers.yGrid
+ .scale(helpers.heightScale)
+ .orient("left")
+ .ticks(5)
+ .tickFormat("");
+
+ helpers.xAxis = d3.svg.axis()
+ .scale(helpers.widthScale)
+ .ticks(5)
+ .orient("bottom")
+ .tickFormat(function(d) {return d;});
+
+ helpers.yAxis = d3.svg.axis()
+ .scale(helpers.heightScale)
+ .ticks(5)
+ .orient("left")
+ .tickFormat(function(d) {return d;});
+
+ helpers.line = d3.svg.line()
+ .x(function(d) { return helpers.widthScale(d[0]); })
+ .y(function(d) { return helpers.heightScale(d[1]); });
+
+ return helpers;
+ }
+
+ function drawGraph(graphHelpers, data, sampleNumber) {
+ svg = d3.select(graphHelpers.selector);
+
+ if (graphHelpers.dynamicHeightDomain) {
+ var limits = [];
+ $.each(data, function(idx, datum) {
+ limits.push(datum.min);
+ limits.push(datum.max);
+ });
+ graphHelpers.heightScale.domain(d3.extent(limits));
+ }
+ graphHelpers.widthScale.domain([(sampleNumber - 299), sampleNumber]);
+
+ svg.select(".x.grid").call(graphHelpers.xGrid);
+ svg.select(".y.grid").call(graphHelpers.yGrid);
+ svg.select(".x.axis").call(graphHelpers.xAxis);
+ svg.select(".y.axis").call(graphHelpers.yAxis);
+
+ var group = svg.select("g.data");
+ var lines = group.selectAll("path").data(data, function(d, i) { return i; });
+ var newLines = lines.enter().append("path").attr("class", "line");
+ lines.attr('d', graphHelpers.line);
+ }
+
MSP.send_message(MSP_codes.MSP_MISC, false, false, get_motor_data);
function get_motor_data() {
@@ -16,6 +134,58 @@ function tab_initialize_motor_outputs() {
// translate to user-selected language
localize();
+ // Always start with default/empty sensor data array, clean slate all
+ initSensorData();
+
+ // Setup variables
+ var samples_accel_i = 0;
+ var accel_data = initDataArray(3);
+ var accelHelpers = initGraphHelpers('#accel', samples_accel_i, [-2, 2]);
+
+ var raw_data_text_ements = {
+ x: [],
+ y: [],
+ z: [],
+ };
+ $('.plot_control .x, .plot_control .y, .plot_control .z').each(function() {
+ var el = $(this);
+ if (el.hasClass('x')) {
+ raw_data_text_ements.x.push(el);
+ } else if (el.hasClass('y')) {
+ raw_data_text_ements.y.push(el);
+ } else {
+ raw_data_text_ements.z.push(el);
+ }
+ });
+
+ $('.tab-motor_outputs .rate select, .tab-motor_outputs .scale select').change(function() {
+ var rate = parseInt($('.tab-motor_outputs select[name="accel_refresh_rate"]').val(), 10);
+ var scale = parseFloat($('.tab-motor_outputs select[name="accel_scale"]').val());
+
+ accelHelpers = initGraphHelpers('#accel', samples_accel_i, [-scale, scale]);
+
+ // timer initialization
+ GUI.interval_kill_all(['motor_pull', 'status_pull']);
+
+ GUI.interval_add('IMU_pull', function imu_data_pull() {
+ MSP.send_message(MSP_codes.MSP_RAW_IMU, false, false, update_accel_graph);
+ }, rate, true);
+
+ function update_accel_graph() {
+ updateGraphHelperSize(accelHelpers);
+
+ samples_accel_i = addSampleToData(accel_data, samples_accel_i, SENSOR_DATA.accelerometer);
+ drawGraph(accelHelpers, accel_data, samples_accel_i);
+ raw_data_text_ements.x[0].text(SENSOR_DATA.accelerometer[0].toFixed(2));
+ raw_data_text_ements.y[0].text(SENSOR_DATA.accelerometer[1].toFixed(2));
+ raw_data_text_ements.z[0].text(SENSOR_DATA.accelerometer[2].toFixed(2));
+ }
+ });
+
+ // fire change event to start accel plot
+ $('.tab-motor_outputs .rate select:first').change();
+
+
// if CAP_DYNBALANCE is true
if (bit_check(CONFIG.capability, 2)) {
$('div.motor_testing').show();
@@ -141,7 +311,7 @@ function tab_initialize_motor_outputs() {
GUI.interval_add('motor_pull', get_motor_data, 50, true);
// status data pulled via separate timer with static speed
- GUI.interval_add('status_pull', function() {
+ GUI.interval_add('status_pull', function get_status_data() {
MSP.send_message(MSP_codes.MSP_STATUS);
}, 250, true);
}