Software cleanup and adding multiple UI’s
Over the last few weeks I was busy working on the implementation of a new UI based on Eric’s ideas.
Around that, there was a lot of cleanup and streamlining done.
Google Ploymer/Webcomponents
With the rework we descided to move a lot of the current and new UI over to Google Polymer based on Webcomponents.
To learn more about Polymer check out the Polymer Project: https://www.polymer-project.org/
Extending the UI with additional elements
So far, plugins would use jQuery to find elements on the UI that they want to extend, for example adding something to the menu bar.
As this gets a bit tricky with webcomponents (because a so called Shadow DOM is used, basically independent sub documents that are loaded similar to iframe’s) we introduced extensionPoints where you can register your elements.
You can find the extensionPoints on the cockpit object when you define a plugin.
Current extensionPoints are:
cockpit.extensionPoints = {
rovSettings: // * <-- The settings panel
rovDiagnostics: // * <-- The diagnostics panel
videoContainer: // * <-- The video container
keyboardInstructions: // * <-- Keyboard Instructions
buttonPanel: // * <-- the buttons panel
menu: // * <-- the menu bar
inputController: // <-- the input controller
headsUpMenu: // <-- the heads up menu (can be undefined if the menu is not loadded)
}
The extension points marked with a * are jQuery objects and you can use functions like .append()
.
InputController
So far, to register something with the inputController, you would send a message. With the extension points you register things like this:
self.cockpit.extensionPoints.inputController.register(
[{
name: "example.keyBoardMapping",
description: "Example for keymapping.",
defaults: { keyboard: 'alt+0', gamepad: 'X' },
down: function() { console.log('0 down'); },
up: function() { console.log('0 up'); }
}]);
HeadsUpMenu
To register something in the heads-up menu, use this:
var item = {
label: ko.observable("Example menu"),
callback: function () {
alert('example menu item from heads up menu');
item.label(this.label() + " Foo Bar");
}
};
if (this.cockpit.extensionPoints.headsUpMenu) {
this.cockpit.extensionPoints.headsUpMenu.register(item);
}
Messaging
One of the biggest changes beside the UI is certainly the way the UI and the NodeJS communicate.
So far, every UI had to listen to the ‘connection’ event on the io.sockets object.
Now, if you want to listen to something sent by the NodeJS backend:
cockpit.rov.on('plugin.example.message', function(message) {
alert(message);
});
This registers for the message plugin.example.message send by the NodeJS part of the plugin (or another plugin).
You want to send something to the ROV:
cockpit.rov.emit('plugin.example.foo');
On the NodeJS end:
deps.cockpit.on('plugin.example.foo', function() {
deps.cockpit.emit('plugin.example.message', 'bar');
});
If you want to send something from the NodeJS to arduino:
deps.rov.send('arduino_cmd(0)');
To read something from the status response on arduino:
deps.rov.on('status', function (status) {
if ('someArduinoValue' in status) {
// do something with status.someArduinoValue
}
Simplified communication between the ROV/Arduino and the Client/Cockpit
Especially when you’re going development for new plugins with code running on Arduino, you had so far to write quite a bit of boilerplate code to get the messages across the NodeJS backend even if you don’t want to do anything with the values there.
To minimize this boilerplate code use the following code:
deps.rov.registerPassthrough({
messagePrefix: 'plugin.example',
fromROV: [
'example_foo',
'example_bar'
],
toROV: [
'example_to_foo',
'example_to_bar'
]
});
This copies all the messages that come from the ROV (in this case example_foo and example_bar) over to the cockpit, prefixing it with plugin.example..
On the other hand, messages from the UI plugin.example.example_to_foo and plugin.example.example_to_bar are stripped of their prefix and forwarded to Arduino.
Cleanup
Beside the changes mentioned above there was a ton of cleanup done.
Where the rovpilot and capestatus plugins where pretty intermixed so far, they are now split and have actually no direct interactions with the UI itself beside the settings and diagnostics. All the UI action is now done via messages and webcomponents.
Beside that, a lot of processing was done on the client and only ‘status’ messages where sent from the backend to the client.
This was changed so that the actual handling is done on the NodeJS side.
This means that we have now the option to interact with the NodeJS end from other frontends, for example from other languages.
Messages that can be sent to the ROV:
videoStatus
ping
update_settings
disconnect
arduinofirmware-startupload
arduinofirmware-uploadfromsource
arduinofirmware-upload
plugin-finder.search
plugin-finder.list
plugin-finder.install
plugin-finder.uninstall
plugin.cameraTilt.set
plugin.cameraTilt.adjust
plugin.diveprofile.watertype.toggle
plugin.laser.toggle
plugin.lights.toggle
plugin.lights.adjust
callibrate_escs
motor-diag.motorTest
plugin.navigationData.zeroDepth
plugin.navigationData.calibrateCompass
plugin.photoCapture.snapshot
rovpilot.allStop
rovpilot.setThrottle
rovpilot.setYaw
rovpilot.setLift
rovpilot.setPitchControl
rovpilot.setRollControl
rovpilot.setPowerLevel
rovpilot.adjustVerticalTrim
rovpilot.adjustThrottleTrim
rovpilot.incrementPowerLevel
rovpilot.powerOnESCs
rovpilot.powerOffESCs
rovpilot.headingHold.toggle
rovpilot.headingHold.set
rovpilot.depthHold.toggle
rovpilot.depthHold.set
rovpilot.manualMotorThrottle
rovpilot.disable
rovpilot.enable
rovpilot.powerLevel.request
plugin.serial-monitor.toggle
Messages from the ROV:
arduinoFirmware-output
arduinofirmware-requestmoredata
arduinoFirmware-status
arduinofirmware-uploaddone
capestatus.battery.config
capestatus.battery.current.out
capestatus.battery.voltage
capestatus.connection.connected
capestatus.connection.disconnected
capestatus.cpu
capestatus.request.battery.config
capestatus.time.runtime
capestatus.time.time
cockpit.pluginsLoaded
plugin.cameraTilt.angle
plugin.input.gamepad.connected
plugin.input.gamepad.disconnected
plugin.laser.disabled
plugin.laser.enabled
plugin.lights.level
plugin.navigationData.data
plugin.photoCapture.photos.added
plugin.photoCapture.photos.updated
plugin.serial-monitor.serial-received
plugin.telemetry.cycleTextColor
plugin.telemetry.logData
pong
rovpilot.control_update
rovpilot.depthHold.disabled
rovpilot.depthHold.enabled
rovpilot.headingHold.disabled
rovpilot.headingHold.enabled
rovpilot.powerLevel
rovsys
settings
status
Roadmap
Currently, the development is done on https://github.com/codewithpassion/openrov-software/tree/feature/new-ui.
In the next few days there will be a lot of testing done and then it should end up in master pretty soon.
What do you think?
What would you like to see?