From d128bd76a569a476a33359550e4259cbbbc4ef40 Mon Sep 17 00:00:00 2001 From: cTn Date: Wed, 25 Jun 2014 13:01:21 +0200 Subject: [PATCH] initial implementation of accel graph in motors tab --- tabs/motor_outputs.css | 238 +++++++++++++++++++++++++++------------- tabs/motor_outputs.html | 68 +++++++++--- tabs/motor_outputs.js | 172 ++++++++++++++++++++++++++++- 3 files changed, 387 insertions(+), 91 deletions(-) diff --git a/tabs/motor_outputs.css b/tabs/motor_outputs.css index df065c97c9..7009952803 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 f6e1e70da1..72e0853ea5 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 0e5ace667e..c3bf1058a5 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); }