Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Frontend: from jQuery to Mercury #19

Open
wants to merge 44 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
f06805d
First experiments with mercury
emersion Feb 13, 2016
5ee2e26
Adds more widgets: mouse direction, charts, system summary
emersion Feb 14, 2016
d2540f3
Refactoring charts, adds new charts widget
emersion Feb 14, 2016
398148a
Adds axis filter to motors speed chart
emersion Feb 14, 2016
eab3d15
Cleanup
emersion Feb 14, 2016
13fb56a
Adds console widget
emersion Feb 14, 2016
80aa735
Adds power input widget, fixes indentation
emersion Feb 14, 2016
0d53f96
Cleanup
emersion Feb 14, 2016
07cb367
Adds rotation input widget
emersion Feb 14, 2016
f29724f
Adds widgets: outline, rotation input and motors summary
emersion Feb 14, 2016
f6ff715
Adds orientation summary widget
emersion Feb 14, 2016
188e979
Adds alerts widget
emersion Feb 14, 2016
3375c2d
Adds warnings when motors reach max power
emersion Feb 14, 2016
40bbd61
Convert indentation to tabs
emersion Feb 15, 2016
0cb7afb
Adds switch component, adds device orientation direction widget
emersion Feb 15, 2016
c31dbb4
Adds step direction widget
emersion Feb 15, 2016
335727b
Adds sine direction widget
emersion Feb 15, 2016
f7024f8
Adds ramp direction widget
emersion Feb 15, 2016
239fc83
Adds gamepad direction widget
emersion Feb 15, 2016
958f545
Adds calibrate btn widget
emersion Feb 15, 2016
eb62ac4
Begins chart recorder
emersion Feb 16, 2016
98b672f
Adds config widget
emersion Feb 16, 2016
52df75a
Merge branch 'mercury' of https://github.com/flying-mole/hud into mer…
emersion Feb 16, 2016
7dc894e
Improves layout for sm devices
emersion Feb 16, 2016
9665de1
Adds export to config form
emersion Feb 16, 2016
801de37
Starting work for camera
emersion Feb 16, 2016
ac55f70
Adds camera profile options
emersion Feb 17, 2016
72d0178
No more NaN while connecting to server in system summary
emersion Feb 19, 2016
41349c5
Adds camera preview widget
emersion Feb 19, 2016
1f0ee29
Finished camera profile widget inputs
emersion Feb 20, 2016
75a0280
Select recorder depending on available commands
emersion Feb 20, 2016
3c20410
Add output option support to avconv recorder
emersion Feb 20, 2016
4300400
Hides camera if not available
emersion Feb 20, 2016
baf4aa2
Adds camera record button
emersion Feb 20, 2016
98b267f
Prevent base updater from appearing in list
emersion Feb 20, 2016
0da1614
Adds basic chart recorder
emersion Feb 20, 2016
82150e7
Fully functional chart recorder
emersion Feb 21, 2016
e7a0ddb
Cleanup
emersion Feb 21, 2016
bc58bf6
Adds camera profile editing, adds bitrate support in avconv
emersion Feb 22, 2016
dc57b2b
(Very) small typos
emersion Mar 4, 2016
82425f7
Begins to send direction
emersion Mar 4, 2016
4fac429
Direction sender is now operational
emersion Mar 5, 2016
d676c1a
Moves rotation input to mouse direction widget
emersion Mar 5, 2016
b63026b
Send new config when changed
emersion Mar 5, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,8 @@ module.exports = {
"vflip": false,
"shutter": null,
"drc": null,
"mode": 1,
"mode": 0,
"bitrate": null,

"width": 400,
"height": 400,
"framerate": 10,
Expand Down
11 changes: 9 additions & 2 deletions lib/camera/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class Camera extends EventEmitter {
}

startRecording() {
var outputPath = '/home/pi/output.h264';
var outputPath = 'output.h264';

var opts = this.config.record;
if (!this.config.previewWhenRecording) {
Expand Down Expand Up @@ -165,13 +165,21 @@ class Camera extends EventEmitter {
reject(err);
});

var exited = false;
recorder.on('exit', function (code) {
if (code === 0) {
resolve();
} else {
reject(code);
}
exited = true;
});

setTimeout(function () {
if (!exited) {
recorder.kill();
}
}, 5000);
});
}
}
Expand Down Expand Up @@ -202,4 +210,3 @@ Camera.defaultOptions = {
};

module.exports = Camera;

87 changes: 52 additions & 35 deletions lib/camera/stream.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var child = require('child_process');
var cmdExists = require('cmd-exists-sync');

var raspivid = function (options) {
options = options || {};
Expand Down Expand Up @@ -29,48 +30,64 @@ var raspivid = function (options) {
});
};

// Doesn't support non-seekable streams with mp4
var avconv = function () {
var avconv = function (options) {
options = options || {};

var args = [
'-i',
'pipe:0',
'-f',
'mp4',
'-loglevel',
'error', // See http://blog.jungkyungsuk.com/tag/loglevel/
'pipe:1'
'-f', 'video4linux2',
'-r', '30000/1001',
'-i', '/dev/video0',
//'-b:a', '2M', // ?
'-bt', '4M',
'-vcodec', 'libx264',
//'-pass', '1',
'-profile:v', 'baseline',
'-coder', '0',
'-bf', '0',
'-flags', '-loop', '-an',
'-bsf:v', 'h264_mp4toannexb',
'-f', 'h264'
];

return child.spawn('avconv', args, {
stdio: ['pipe', 'pipe', 'inherit']
});
};
if (options.timeout) {
args.push('-t');
args.push(options.timeout);
}

// Doesn't support mp4 streaming
var cvlc = function () {
var args = [
'-I',
'dummy',
'-v',
'v4l2:///dev/video0',
'--v4l2-chroma',
'h264',
'--v4l2-width',
'800',
'--v4l2-height',
'600',
'--sout',
//'#standard{access=file,mux=mp4,dst=-}',
'#standard{access=http,mux=ts,dst=0.0.0.0:3001}', // TODO
':demux=h264'
];
if (options.width && options.height) {
args.push('-vf');
args.push('scale='+options.width+':'+options.height);
}

// cvlc v4l2:///dev/video0 --v4l2-width 800 --v4l2-height 600 --v4l2-chroma h264 --sout '#standard{access=http,mux=ts,dst=0.0.0.0:12345}' -vvv
if (options.framerate) {
args.push('-r');
args.push(options.framerate);
}

if (options.bitrate) {
args.push('-b');
args.push(options.bitrate);
}

return child.spawn('cvlc', args, {
if (options.output) {
args.push(options.output);
} else {
args.push('-');
}

console.log('avconv', args.join(' '));

return child.spawn('avconv', args, {
stdio: ['pipe', 'pipe', 'inherit']
});
};

module.exports = raspivid;

if (cmdExists('raspivid')) {
module.exports = raspivid;
} else if (cmdExists('avconv')) {
module.exports = avconv;
} else {
module.exports = function () {
throw new Error('No recorder available');
};
}
18 changes: 10 additions & 8 deletions lib/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ var path = require('path');
var EventEmitter = require('events').EventEmitter;

function loadUpdaters() {
var dir = 'controller';

var updaters = {};
fs.readdirSync(__dirname+'/'+dir).forEach(function (file) {
var name = path.basename(file, '.js');
updaters[name] = require('./'+dir+'/'+name);
});
return updaters;
var dir = 'controller';

var updaters = {};
fs.readdirSync(__dirname+'/'+dir).forEach(function (file) {
var name = path.basename(file, '.js');
if (name[0] === '_') return;

updaters[name] = require('./'+dir+'/'+name);
});
return updaters;
}

var updaters = loadUpdaters();
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion lib/controller/dummy.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

var BaseUpdater = require('./base');
var BaseUpdater = require('./_base');

/**
* A dummy updater.
Expand Down
2 changes: 1 addition & 1 deletion lib/controller/physics-quantif.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

var BaseUpdater = require('./base');
var BaseUpdater = require('./_base');

/**
* The physics updater.
Expand Down
2 changes: 1 addition & 1 deletion lib/controller/physics.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

var BaseUpdater = require('./base');
var BaseUpdater = require('./_base');

/**
* The physics updater.
Expand Down
2 changes: 1 addition & 1 deletion lib/controller/rate-simple.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

var PidController = require('node-pid-controller');
var BaseUpdater = require('./base');
var BaseUpdater = require('./_base');

/**
* A simple rate updater.
Expand Down
2 changes: 1 addition & 1 deletion lib/controller/stabilize-simple.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

var PidController = require('node-pid-controller');
var BaseUpdater = require('./base');
var BaseUpdater = require('./_base');

var forEachPid = Symbol();

Expand Down
5 changes: 3 additions & 2 deletions lib/quadcopter-base.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

var EventEmitter = require('events').EventEmitter;
var extend = require('extend');
var Controller = require('./controller');

/**
Expand Down Expand Up @@ -50,8 +51,8 @@ class QuadcopterBase extends EventEmitter {
set config(config) {
if (typeof config != 'object') throw new Error('Cannot set quadcopter "config" property: must be an object');

this._config = config;
this.emit('config', config);
extend(this._config, config);
this.emit('config', this.config);
}

get power() {
Expand Down
6 changes: 3 additions & 3 deletions lib/quadcopter.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ class Quadcopter extends QuadcopterBase {

that._resetMotorsSpeeds(true);
}, function (err) {
console.error('WARN: cannot load motors', err);
console.error('WARN: cannot load motors:', err);
});

// Then Inertial Measurement Unit
console.log('Loading sensors...');
var promise = loadSensors(this).catch(function (err) {
console.error('WARN: cannot load sensors', err);
console.error('WARN: cannot load sensors:', err);
}).then(function (sensors) {
that.sensors = sensors || {};
if (that.sensors.mpu6050) {
Expand All @@ -58,7 +58,7 @@ class Quadcopter extends QuadcopterBase {
return that.camera.check().then(function () {
that.features.push('camera');
}, function (err) {
console.error('WARN: camera not available', err);
console.error('WARN: camera not available:', err);
});
}).then(function () {
// Ready :-)
Expand Down
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,27 @@
"dependencies": {
"bootstrap": "^3.3.6",
"broadway-player": "^0.1.1",
"browser-request": "^0.3.3",
"c3": "^0.4.11-rc4",
"cmd-exists-sync": "^0.1.0",
"events": "^1.0.2",
"expand-flatten": "^1.0.0",
"express": "^4.12.3",
"express-browserify-lite": "^0.1.2",
"express-ws": "^0.2.6",
"extend": "^2.0.1",
"global": "^4.3.0",
"i2c-bus": "^0.11.1",
"i2c-mpu6050": "^2.2.0",
"jquery": "^2.2.0",
"mercury": "^14.1.0",
"mpu6050-dmp": "^0.0.6",
"msgpack5": "^3.3.0",
"node-pid-controller": "^0.1.2",
"round-to": "^1.1.0",
"servoblaster": "^0.1.0",
"smoothie": "^1.27.0",
"stream-split": "^0.2.0",
"svg-injector": "^1.1.3",
"throttleit": "^1.0.0",
"through": "^2.3.8",
"util": "^0.10.3"
}
Expand Down
39 changes: 28 additions & 11 deletions public/assets/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,19 @@ template {
box-shadow: none;
border-bottom-color: rgba(0, 100, 200, 0.3);
}
.form-control:invalid {
border-bottom-color: rgba(255, 0, 0, 0.2);
}
input[type="number"].form-control {
-moz-appearance: textfield;
}

.form-inline input[type="number"].form-control {
width: 65px;
}
.form-inline input[type="number"][size="1"].form-control {
width: 35px;
}

#console {
height: 200px;
Expand All @@ -98,15 +104,15 @@ input[type="number"].form-control {
color: rgb(0, 100, 0);
}

.joystick {
.direction-mouse {
position: relative;
width: 300px;
height: 300px;
border: 5px solid rgba(211, 211, 211, 0.2);
border-radius: 50%;
margin: 10px auto;
}
.joystick .handle {
.direction-mouse .handle {
position: absolute;
width: 16px;
height: 16px;
Expand All @@ -115,7 +121,17 @@ input[type="number"].form-control {
opacity: 0.2;
pointer-events: none;
}
.joystick.active .handle {
.direction-mouse .handle .tooltip {
width: 100px;
top: -35px;
left: -42px;
}
.direction-mouse:active .handle,
.direction-mouse.active .handle {
opacity: 1;
}
.direction-mouse:active .handle .tooltip,
.direction-mouse.active .handle .tooltip {
opacity: 1;
}

Expand Down Expand Up @@ -150,10 +166,8 @@ input[type="range"][orient="vertical"]::-moz-range-track {
width: 5px;
}

#power-input {
width: 100px;
.power-input {
height: 300px;
margin: auto;
}

select {
Expand Down Expand Up @@ -242,21 +256,24 @@ select {
border-color: rgba(0, 100, 200, 0.3);
}

.quadcopter-schema {
.quadcopter-outline {
margin: auto;
}
.quadcopter-outline svg {
fill: rgb(58, 58, 58);
transition: 0.2s transform;
}
.quadcopter-schema g {
.quadcopter-outline g {
transition: 0.2s fill;
}
#quadcopter-top {
#quadcopter-outline-top {
width: 300px;
height: 300px;
}
.quadcopter-side {
.quadcopter-outline-side {
width: 300px;
height: 75px;
margin: 37px 0;
margin-top: 37px;
}

#camera-video canvas {
Expand Down
Loading