1
0
Fork 0
mirror of https://github.com/iNavFlight/inav-configurator.git synced 2025-07-23 00:05:19 +03:00

WIP: Add magnetometer alignment tab

This commit is contained in:
Hofer Lukas 2022-02-09 23:58:30 +01:00
parent 979199cd69
commit 15c697daf7
9 changed files with 571 additions and 1 deletions

View file

@ -115,6 +115,9 @@
"tabGPS": { "tabGPS": {
"message": "GPS" "message": "GPS"
}, },
"tabMagnetometer": {
"message": "Magnetometer"
},
"tabOutputs": { "tabOutputs": {
"message": "Outputs" "message": "Outputs"
}, },
@ -768,6 +771,15 @@
"configurationSensorAlignmentMag": { "configurationSensorAlignmentMag": {
"message": "MAG Alignment" "message": "MAG Alignment"
}, },
"configurationSensorAlignmentMagRoll": {
"message": "Roll Degrees"
},
"configurationSensorAlignmentMagPitch": {
"message": "Pitch Degrees"
},
"configurationSensorAlignmentMagYaw": {
"message": "Yaw Degrees"
},
"configurationAccelTrims": { "configurationAccelTrims": {
"message": "Accelerometer Trim" "message": "Accelerometer Trim"
}, },
@ -1692,6 +1704,15 @@
"gpsSignalStr": { "gpsSignalStr": {
"message": "Signal Strength" "message": "Signal Strength"
}, },
"magnetometerHead": {
"message": "Magnetometer Alignment"
},
"configurationMagnetometerHelp": {
"message": "<strong>Note:</strong> Remember to configure a Serial Port (via Ports tab) when using the Magnetometer feature."
},
"magnetometerStatHead": {
"message": "Mag Statistics"
},
"motors": { "motors": {
"message": "Motors" "message": "Motors"
}, },

View file

@ -24,6 +24,7 @@ var GUI_control = function () {
'cli', 'cli',
'configuration', 'configuration',
'gps', 'gps',
'magnetometer',
'led_strip', 'led_strip',
'logging', 'logging',
'onboard_logging', 'onboard_logging',

View file

@ -1643,7 +1643,7 @@ dialog {
/* fixing padding for all Tabs*/ /* fixing padding for all Tabs*/
.tab-setup, .tab-landing, .tab-adjustments, .tab-auxiliary, .tab-cli, .tab-configuration, .tab-failsafe, .tab-onboard_logging, .tab-setup, .tab-landing, .tab-adjustments, .tab-auxiliary, .tab-cli, .tab-configuration, .tab-failsafe, .tab-onboard_logging,
.tab-firmware_flasher, .tab-gps, .tab-help, .tab-led-strip, .tab-logging, .tab-modes, .tab-motors, .tab-pid_tuning, .tab-firmware_flasher, .tab-gps, .tab-magnetometer, .tab-help, .tab-led-strip, .tab-logging, .tab-modes, .tab-motors, .tab-pid_tuning,
.tab-ports, .tab-receiver, .tab-sensors, .tab-servos, .tab-osd, .tab-calibration { .tab-ports, .tab-receiver, .tab-sensors, .tab-servos, .tab-osd, .tab-calibration {
height: 100%; height: 100%;
position: relative; position: relative;

View file

@ -225,6 +225,9 @@
<li class="tab_gps"> <li class="tab_gps">
<a href="#" data-i18n="tabGPS" class="tabicon ic_gps" title="GPS"></a> <a href="#" data-i18n="tabGPS" class="tabicon ic_gps" title="GPS"></a>
</li> </li>
<li class="tab_magnetometer">
<a href="#" data-i18n="tabMAGNETOMETER" class="tabicon ic_mag" title="MAGNETOMETER"></a>
</li>
<li class="tab_mission_control"> <li class="tab_mission_control">
<a href="#" data-i18n="tabMissionControl" class="tabicon ic_mission" title="Mission Control"></a> <a href="#" data-i18n="tabMissionControl" class="tabicon ic_mission" title="Mission Control"></a>
</li> </li>

View file

@ -248,6 +248,9 @@ $(document).ready(function () {
case 'gps': case 'gps':
TABS.gps.initialize(content_ready); TABS.gps.initialize(content_ready);
break; break;
case 'magnetometer':
TABS.magnetometer.initialize(content_ready);
break;
case 'mission_control': case 'mission_control':
TABS.mission_control.initialize(content_ready); TABS.mission_control.initialize(content_ready);
break; break;

34
resources/models/gps.json Normal file
View file

@ -0,0 +1,34 @@
{
"name": "CubeGeometry",
"faces": [33,0,1,2,3,0,1,2,3,33,4,7,6,5,4,5,6,7,33,0,4,5,1,0,4,7,1,33,1,5,6,2,1,7,6,2,33,2,6,7,3,2,6,5,3,33,4,0,3,7,4,0,3,5],
"uvs": [],
"vertices": [1,-0.2,-1,1,-0.2,1,-1,-0.2,1,-1,-0.2,-1,1,0.2,-0.999999,0.999999,0.2,1,-1,0.2,1,-1,0.2,-1],
"normals": [0.577349,-0.577349,-0.577349,0.577349,-0.577349,0.577349,-0.577349,-0.577349,0.577349,-0.577349,-0.577349,-0.577349,0.577349,0.577349,-0.577349,-0.577349,0.577349,-0.577349,-0.577349,0.577349,0.577349,0.577349,0.577349,0.577349],
"metadata": {
"type": "Geometry",
"generator": "io_three",
"faces": 6,
"uvs": 0,
"vertices": 8,
"normals": 8,
"version": 3
},
"materials": [{
"DbgColor": 15658734,
"specularCoef": 50,
"colorEmissive": [0.0,0.0,0.0],
"colorAmbient": [1.0,0.0,0.0],
"colorDiffuse": [1.0,0.0,0.0],
"transparent": false,
"depthWrite": true,
"colorSpecular": [0.25,0.25,0.25],
"DbgName": "Material.005",
"wireframe": false,
"shading": "phong",
"depthTest": true,
"visible": true,
"blending": "NormalBlending",
"DbgIndex": 0,
"opacity": 1.0
}]
}

View file

@ -0,0 +1,148 @@
/* TODO This needs a LOT of work. It's basically just the GPS tab copied */
.tab-magnetometer progress {
width: 100%;
border-radius: 3px;
}
.tab-magnetometer .magnetometer_info .head, .tab-magnetometer .magnetometer_signal_strength .head {
display: block;
text-align: center;
line-height: 20px;
font-weight: bold;
border-bottom: 1px solid silver;
background-color: #ececec;
}
.tab-magnetometer #connect {
display: none;
text-align: center;
padding-top: 40%;
}
.tab-magnetometer #waiting {
margin-top: 0;
display: none;
text-align: center;
padding-top: 0;
background-size: 15%;
min-height: 400px;
background: url(../../../images/loading-bars.svg) no-repeat center 40%;
float: left;
width: 100%;
}
.tab-magnetometer #waiting .info {
margin-top: 30%;
}
/* .tab-magnetometer #loadmap {
margin-top: 0;
display: none;
} */
.tab-magnetometer #connect a {
font-weight: bold;
margin-top: 10px;
}
.tab-magnetometer #loadmap {
height: 100%;
width: 100%;
float: left;
}
.map-button {
z-index:1;
position: absolute;
background-color: #37A8DB;
color: white;
padding: 5px;
left: 10px;
bottom: 10px;
border-style: solid;
border-width: 2px;
border-color: #E4E4E4;
border-radius: 2px;
opacity: 0.8;
}
.map-button:hover {
opacity: 1;
}
.tab-magnetometer #loadmap .controls {
width: 100%;
float: left;
height: 33px;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
background-color: #D1D1D1;
}
.tab-magnetometer #loadmap .controls a {
background-color: white;
border-radius: 4px;
border: 1px silver solid;
color: grey;
height: 10px;
width: 10px;
text-align: center;
font-size: 20px;
line-height: 10px;
padding: 6px;
margin-top: 5px;
float: right;
}
.tab-magnetometer #loadmap .controls a:hover {
background-color: #f5f5f5;
}
.tab-magnetometer #loadmap .controls a:active {
background-color: #e6e6e6;
}
.tab-magnetometer #loadmap .controls a:first-child {
margin-left: -1px;
margin-right: 5px;
border-bottom-left-radius: 0;
border-top-left-radius: 0;
}
.tab-magnetometer #loadmap .controls a:last-child {
margin-right: 0;
border-bottom-right-radius: 0;
border-top-right-radius: 0;
}
#magnetometer-map {
height: 400px;
width: 100%;
float: left;
position: relative;
}
/*noinspection ALL*/
progress[value]::-webkit-progress-bar {
background-color: #d2d2d2;
border-radius: 2px;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.25) inset;
}
/*noinspection ALL*/
progress[value]::-webkit-progress-value {
background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, .15), rgba(0, 0, 0, .15)),
-webkit-linear-gradient(left, #39a9dc, #39a9dc);
border-radius: 2px;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.25) inset;
}
@media only screen and (max-width: 1055px) , only screen and (max-device-width: 1055px) {
#magnetometer-map {
height: 347px;
width: 100%;
float: left;
}
}

74
tabs/magnetometer.html Normal file
View file

@ -0,0 +1,74 @@
<div class="tab-magnetometer">
<div class="content_wrapper" style="height: calc(100% - 40px)">
<div class="tab_title" data-i18n="tabMagnetometer">Magnetometer</div>
<div class="cf_column fourth">
<div class="spacer_right">
<div class="config-section gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" data-i18n="magnetometerHead"></div>
</div>
<div class="spacer_box">
<div class="note">
<div class="note_spacer">
<p data-i18n="configurationMagnetometerHelp"></p>
</div>
</div>
<div class="select">
<select id="magalign" class="magalign">
<option value="0">Default</option>
<!-- list generated here -->
</select>
<label for="magalign" data-i18n="configurationSensorAlignmentMag"></label>
</div>
<div class="number">
<input type="number" id="alignRoll" data-setting="tz_offset" data-setting-multiplier="1" step="1" min="-180" max="180" />
<label for="alignRoll">
<span data-i18n="configurationSensorAlignmentMagRoll"></span>
</label>
</div>
<div class="number">
<input type="number" id="alignPitch" data-setting="tz_offset" data-setting-multiplier="1" step="1" min="-180" max="180" />
<label for="alignPitch">
<span data-i18n="configurationSensorAlignmentMagPitch"></span>
</label>
</div>
<div class="number">
<input type="number" id="alignYaw" data-setting="tz_offset" data-setting-multiplier="1" step="1" min="-180" max="180" />
<label for="alignYaw">
<span data-i18n="configurationSensorAlignmentMagYaw"></span>
</label>
</div>
</div>
</div>
</div>
</div>
<div class="cf_column threefourth_left" style="height: calc(100% - 100px);">
<div class="gui_box grey magnetometer_model">
<div class="gui_box_titlebar" style="margin-bottom: 0;">
<div class="spacer_box_title" data-i18n="magnetometerMapHead"></div>
</div>
<div id="model">
<div class="model-and-info">
<div id="interactive_block">
<div id="canvas_wrapper">
<canvas id="canvas"></canvas>
</div>
<a class="reset" href="#" data-i18n="initialSetupButtonResetZaxis"></a>
</div>
</div>
</div>
</div>
</div>
<div class="content_toolbar">
<div class="btn save_btn">
<a class="save" href="#" data-i18n="configurationButtonSave"></a>
</div>
</div>
</div>
</div>

286
tabs/magnetometer.js Normal file
View file

@ -0,0 +1,286 @@
'use strict';
/*global chrome,GUI,TABS,nwdialog,$*/
TABS.magnetometer = {};
TABS.magnetometer.initialize = function (callback) {
var self = this;
if (GUI.active_tab != 'magnetometer') {
GUI.active_tab = 'magnetometer';
googleAnalytics.sendAppView('MAGNETOMETER');
}
self.alignmentConfig = {
pitch: 0,
roll: 0,
yaw: 0
};
//========================
// Load chain
// =======================
var loadChainer = new MSPChainerClass();
var loadChain = [
mspHelper.loadMixerConfig,
mspHelper.loadSensorAlignment,
function(callback) {
mspHelper.getSetting("align_mag_roll").then(function (data) {
self.alignmentConfig.roll = parseInt(data.value, 10) / 10;
}).then(callback)
},
function(callback) {
mspHelper.getSetting("align_mag_pitch").then(function (data) {
self.alignmentConfig.pitch = parseInt(data.value, 10) / 10;
}).then(callback)
},
function(callback) {
mspHelper.getSetting("align_mag_yaw").then(function (data) {
self.alignmentConfig.yaw = parseInt(data.value, 10) / 10;
}).then(callback)
}
];
loadChainer.setChain(loadChain);
loadChainer.setExitPoint(load_html);
loadChainer.execute();
//========================
// Save chain
// =======================
var saveChainer = new MSPChainerClass();
var saveChain = [
// Magnetometer alignment
function (callback) {
let orientation_mag_e = $('select.magalign');
SENSOR_ALIGNMENT.align_mag = parseInt(orientation_mag_e.val());
callback();
},
mspHelper.saveSensorAlignment,
// Pitch/Roll/Yaw
function(callback) {
mspHelper.setSetting("align_mag_roll", self.alignmentConfig.roll * 10, callback);
},
function(callback) {
mspHelper.setSetting("align_mag_pitch", self.alignmentConfig.pitch * 10, callback);
},
function(callback) {
mspHelper.setSetting("align_mag_yaw", self.alignmentConfig.yaw * 10, callback);
},
mspHelper.saveToEeprom
];
saveChainer.setChain(saveChain);
saveChainer.setExitPoint(reboot);
function reboot() {
//noinspection JSUnresolvedVariable
GUI.log(chrome.i18n.getMessage('configurationEepromSaved'));
GUI.tab_switch_cleanup(function () {
MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false, reinitialize);
});
}
function reinitialize() {
GUI.log(chrome.i18n.getMessage('deviceRebooting'));
GUI.handleReconnect($('.tab_magnetometer a'));
}
function load_html() {
GUI.load("./tabs/magnetometer.html", process_html);
}
function process_html() {
localize();
// initialize 3D
self.initialize3D();
self.render3D();
let alignments = FC.getSensorAlignments();
let orientation_mag_e = $('select.magalign');
let orientation_mag_roll = $('#alignRoll');
let orientation_mag_pitch = $('#alignPitch');
let orientation_mag_yaw = $('#alignYaw');
for (i = 0; i < alignments.length; i++) {
orientation_mag_e.append('<option value="' + (i + 1) + '">' + alignments[i] + '</option>');
}
orientation_mag_e.val(SENSOR_ALIGNMENT.align_mag);
orientation_mag_roll.val(self.alignmentConfig.roll);
orientation_mag_pitch.val(self.alignmentConfig.pitch);
orientation_mag_yaw.val(self.alignmentConfig.yaw);
function clamp(input, min, max) {
return Math.min(Math.max(parseInt($(input).val()), min), max);
}
orientation_mag_e.change(function () {
SENSOR_ALIGNMENT.align_mag = parseInt($(this).val());
self.render3D();
});
orientation_mag_roll.change(function () {
self.alignmentConfig.roll = clamp(this, -180, 180);
self.render3D();
});
orientation_mag_pitch.change(function () {
self.alignmentConfig.pitch = clamp(this, -180, 180)
self.render3D();
});
orientation_mag_yaw.change(function () {
self.alignmentConfig.yaw = clamp(this, -180, 360);
self.render3D();
});
$('a.save').click(function () {
saveChainer.execute()
});
GUI.content_ready(callback);
}
};
TABS.magnetometer.initialize3D = function () {
var self = this,
loader,
canvas,
wrapper,
renderer,
camera,
scene,
light,
light2,
model,
model_file,
gps_model,
useWebGlRenderer = false;
canvas = $('.model-and-info #canvas');
wrapper = $('.model-and-info #canvas_wrapper');
// webgl capability detector
// it would seem the webgl "enabling" through advanced settings will be ignored in the future
// and webgl will be supported if gpu supports it by default (canary 40.0.2175.0), keep an eye on this one
var detector_canvas = document.createElement('canvas');
if (window.WebGLRenderingContext && (detector_canvas.getContext('webgl') || detector_canvas.getContext('experimental-webgl'))) {
renderer = new THREE.WebGLRenderer({canvas: canvas.get(0), alpha: true, antialias: true});
useWebGlRenderer = true;
} else {
renderer = new THREE.CanvasRenderer({canvas: canvas.get(0), alpha: true});
}
// initialize render size for current canvas size
renderer.setSize(wrapper.width()*2, wrapper.height()*2);
// load the model including materials
if (useWebGlRenderer) {
if (MIXER_CONFIG.appliedMixerPreset === -1) {
model_file = 'custom';
GUI_control.prototype.log("<span style='color: red; font-weight: bolder'><strong>" + chrome.i18n.getMessage("mixerNotConfigured") + "</strong></span>");
} else {
model_file = helper.mixer.getById(MIXER_CONFIG.appliedMixerPreset).model;
}
} else {
model_file = 'fallback'
}
// Temporary workaround for 'custom' model until akfreak's custom model is merged.
if (model_file == 'custom') {
model_file = 'fallback';
}
// setup scene
scene = new THREE.Scene();
loader = new THREE.JSONLoader();
loader.load('./resources/models/' + model_file + '.json', function (geometry, materials) {
var modelMaterial = new THREE.MeshFaceMaterial(materials);
model = new THREE.Mesh(geometry, modelMaterial);
model.scale.set(10, 10, 10);
scene.add(model);
loader.load('./resources/models/gps.json', function (geometry, materials) {
var modelMaterial = new THREE.MeshFaceMaterial(materials);
gps_model = new THREE.Mesh(geometry, modelMaterial);
gps_model.scale.set(5, 5, 5);
// TODO This should depend on the selected drone model
gps_model.position.set(0, 0, 25);
scene.add(gps_model);
self.render3D();
}, function() { console.log("Couldn't load model file", arguments)});
}, function() { console.log("Couldn't load model file", arguments)});
// stationary camera
camera = new THREE.PerspectiveCamera(50, wrapper.width() / wrapper.height(), 1, 10000);
// some light
light = new THREE.AmbientLight(0x404040);
light2 = new THREE.DirectionalLight(new THREE.Color(1, 1, 1), 1.5);
light2.position.set(0, 1, 0);
// move camera away from the model
camera.position.z = 0;
camera.position.y = 50;
camera.position.x = -90;
camera.lookAt(new THREE.Vector3(0, 0, 0));
// add camera, model, light to the foreground scene
scene.add(light);
scene.add(light2);
scene.add(camera);
this.render3D = function () {
if (!model) {
return;
}
gps_model.rotation.x = THREE.Math.degToRad(self.alignmentConfig.pitch);
gps_model.rotation.y = THREE.Math.degToRad(self.alignmentConfig.yaw);
gps_model.rotation.z = THREE.Math.degToRad(self.alignmentConfig.roll);
// draw
renderer.render(scene, camera);
};
// handle canvas resize
this.resize3D = function () {
renderer.setSize(wrapper.width() * 2, wrapper.height() * 2);
camera.aspect = wrapper.width() / wrapper.height();
camera.updateProjectionMatrix();
self.render3D();
};
$(window).on('resize', this.resize3D);
this.render3D()
};
TABS.magnetometer.cleanup = function (callback) {
$(window).off('resize', this.resize3D);
if (callback) callback();
};