4 <meta charset="utf-8" />
6 <link rel="stylesheet" href="assets/stylesheets/bootstrap.min.css">
7 <link rel="stylesheet" href="assets/stylesheets/jquery-ui.css">
8 <link rel="stylesheet" href="assets/stylesheets/jquery.minicolors.css">
11 .minicolors-theme-default.minicolors { margin: 5px; }
12 .bottom-leds > .minicolors-theme-default.minicolors { margin: 5px 0; }
13 .top-leds > .minicolors-theme-default.minicolors { margin-top: 70px; }
14 .wt-icon {background: url('assets/images/wt_top.png'); background-size: cover; background-size: 100%; background-repeat: no-repeat; background-position: center; height: 260px;}
18 background-color: #bbb;
20 display: inline-block;
24 <script type="text/javascript">
26 var ros = new ROSLIB.Ros();
27 ros.connect('ws://wildthumper:9090');
28 var isDragging = false;
30 ros.on('connection', function() {
31 information.alerts.push({message: "Connected to websocket server.", success: true});
34 ros.on('error', function(error) {
35 information.alerts.push({message: "Error connecting to websocket server.", danger: true});
38 ros.on('close', function() {
39 information.alerts.push({message: "Connection to websocket server closed.", info: true});
42 //tfClient.subscribe('base_link', function(tf) {
43 // var now = new Date();
44 // $("#pose").text(now.toLocaleTimeString() + ": (" + tf.translation.x + ", " + tf.translation.y + ")");
46 // robotMarker.x = tf.translation.x;
47 // robotMarker.y = -tf.translation.y;
48 // robotMarker.rotation = viewer2D.scene.rosQuaternionToGlobalTheta(tf.rotation);
50 var poseTopic = new ROSLIB.Topic({ros: ros, name: '/robot_pose', messageType: 'geometry_msgs/Pose'});
51 var sensorTopic = new ROSLIB.Topic({ros: ros, name: '/sensors', messageType: 'wild_thumper/Sensor'});
52 var batteryTopic = new ROSLIB.Topic({ros: ros, name: '/battery', messageType: 'sensor_msgs/BatteryState'});
53 var ledStripeTopic = new ROSLIB.Topic({ros: ros, name: '/led_stripe', messageType: 'wild_thumper/LedStripe'});
54 var cmdVelTopic = new ROSLIB.Topic({ros: ros, name: '/teleop/cmd_vel', messageType: 'geometry_msgs/Twist'});
56 poseTopic.subscribe(function(message) {
58 $("#pose").text(now.toLocaleTimeString() + ": (" + message.position.x + ", " + message.position.y + ")");
61 sensorTopic.subscribe(function(message) {
62 sensors.light = message.light;
63 sensors.temp = message.temp.toFixed(1);
64 sensors.humidity = message.humidity;
65 sensors.pressure = message.pressure.toFixed(1);
66 sensors.co = message.co;
69 batteryTopic.subscribe(function(message) {
70 power.voltage = message.voltage.toFixed(1);
71 power.current = message.current.toFixed(1);
74 viewer2D = new ROS2D.Viewer({
81 .bind('mousewheel', function(e) {
82 if (e.originalEvent.wheelDelta/120 > 0) {
83 viewer2D.scaleToDimensions(10, 10)
85 viewer2D.scaleToDimensions(5, 5)
88 .mousedown(function() {
90 mousePreX = undefined;
91 mousePreY = undefined;
96 .mousemove(function(event) {
98 if (mousePreX != undefined && mousePreY != undefined) {
99 var diffX = event.pageX - mousePreX;
100 var diffY = event.pageY - mousePreY;
101 console.log("Moving viewer2D by " + diffX + ", " + diffY);
102 viewer2D.shift(diffX, diffY);
104 mousePreX = event.pageX;
105 mousePreY = event.pageY;
109 // Setup the nav client.
110 NAV2D.OccupancyGridClientNav({
112 rootObject : viewer2D.scene,
114 serverName : '/move_base'
117 // Initialize the teleop.
118 teleop = new KEYBOARDTELEOP.Teleop({
120 topic : '/teleop/cmd_vel'
123 // Create a UI slider using JQuery UI.
124 $('#speed-slider').slider({
130 slide : function(event, ui) {
131 // Change the speed label.
132 speed_label.speed = ui.value;
134 teleop.scale = (ui.value * 2);
138 // Set the initial speed.
139 teleop.scale = ($('#speed-slider').slider('value') * 2);
141 $('.led_color').minicolors({
144 defaultValue: '#000000',
145 change: function(value) {
146 var rgb = $(this).minicolors('rgbObject');
147 var nums = jQuery.parseJSON($(this).prop("name"));
148 var msg = new ROSLIB.Message({
151 jQuery.each(nums, function(i, num) {
154 red: parseInt(rgb.r*127/255),
155 green: parseInt(rgb.g*127/255),
156 blue: parseInt(rgb.b*127/255)
159 ledStripeTopic.publish(msg);
163 function setSpeed(trans, rot) {
164 var msg = new ROSLIB.Message({
176 cmdVelTopic.publish(msg);
180 .bind('mousedown touchstart', function(e) {
183 .bind('mouseup touchend mouseleave', function(e) {
187 .bind('mousemove touchmove', function(e) {
189 // absolute click position
191 if (e.originalEvent.touches) {
192 X = e.originalEvent.touches[0].pageX;
193 Y = e.originalEvent.touches[0].pageY;
198 // relative click position
199 var Xrel = X - this.offsetLeft - $(this).width()/2;
200 var Yrel = Y - this.offsetTop - $(this).height()/2;
202 var trans = -Yrel / ($(this).height()/2);
203 var rot = -Xrel / ($(this).width()/2);
204 setSpeed(trans, rot*3);
208 information = new Vue({
214 classObject: function(id) {
216 "alert-success": this.alerts[id].success,
217 "alert-danger": this.alerts[id].danger,
218 "alert-info": this.alerts[id].info
226 data: {light: '', temp: '', humidity: '', pressure: '', co: ''}
237 speed_label = new Vue({
240 speed: $('#speed-slider').slider('value'),
245 <title>Wild Thumper control</title>
247 <body onload="init()">
248 <div class="container-fluid">
249 <div id="information">
250 <div v-for="(alert, id) in alerts" class="alert alert-dismissible}" v-bind:class="classObject(id)">
251 <span data-dismiss="alert">{{alert.message}}</span>
255 <nav class="navbar navbar-expand-lg navbar-light bg-light">
256 <a class="navbar-brand" href="#">Wild Thumper</a>
257 <ul class="nav nav-tabs" role="tablist">
258 <li class="nav-item">
259 <a class="nav-link active" href="#data" data-toggle="tab" role="tab">Data</a>
261 <li class="nav-item">
262 <a class="nav-link" href="#navigation" data-toggle="tab" role="tab">Navigation</a>
264 <li class="nav-item">
265 <a class="nav-link" href="#lights" data-toggle="tab" role="tab">Lights</a>
267 <li class="nav-item">
268 <a class="nav-link" href="#drive" data-toggle="tab" role="tab">Drive</a>
272 <div class="tab-content">
273 <div id="data" class="tab-pane active" role="tabpanel">
275 <div id="power" class="col-auto">
277 <label>Voltage:</label>
278 <div class="input-group">
279 <input type=text name="voltage" class="form-control" v-model="voltage" readonly>
280 <div class="input-group-append">
281 <span class="input-group-text">V</span>
284 <label>Current:</label>
285 <div class="input-group">
286 <input type=text name="current" class="form-control" v-model="current" readonly>
287 <div class="input-group-append">
288 <span class="input-group-text">A</span>
292 <div id="sensors" class="col-auto">
294 <label>Light:</label>
295 <div class="input-group">
296 <input type=text name="light" class="form-control" v-model="light" readonly>
297 <div class="input-group-append">
298 <span class="input-group-text">lx</span>
301 <label>Temperature:</label>
302 <div class="input-group">
303 <input type=text name="temp" class="form-control" v-model="temp" readonly>
304 <div class="input-group-append">
305 <span class="input-group-text">℃</span>
308 <label>Humidity:</label>
309 <div class="input-group">
310 <input type=text name="humidity" class="form-control" v-model="humidity" readonly>
311 <div class="input-group-append">
312 <span class="input-group-text">%</span>
315 <label>Pressure:</label>
316 <div class="input-group">
317 <input type=text name="pressure" class="form-control" v-model="pressure" readonly>
318 <div class="input-group-append">
319 <span class="input-group-text">kPa</span>
323 <input type=text name="co" class="form-control" v-model="co" readonly>
327 <div id="navigation" class="tab-pane" role="tabpanel">
328 <div id="pose"></div>
330 <div id="speed-label">Speed: {{speed}} m/s</div>
331 <div id="speed-slider"></div>
333 <div id="lights" class="tab-pane" role="tabpanel">
335 <div class="col-md-2 offset-md-1" >
336 <div class="d-flex justify-content-center">
337 <input class="led_color" type="hidden" name="[0]" readonly="true"/>
338 <input class="led_color" type="hidden" name="[1]" readonly="true"/>
339 <input class="led_color" type="hidden" name="[2]" readonly="true"/>
340 <input class="led_color" type="hidden" name="[3]" readonly="true"/>
343 <div class="row wt-icon">
344 <div class="col-md-2 align-self-center bottom-leds">
345 <input class="led_color" type="hidden" name="[14]" readonly="true"/>
346 <input class="led_color" type="hidden" name="[15]" readonly="true"/>
348 <div class="col-md-8">
349 <div class="d-flex justify-content-center top-leds">
350 <input class="led_color" type="hidden" name="[7]" readonly="true"/>
351 <input class="led_color" type="hidden" name="[6]" readonly="true"/>
352 <input class="led_color" type="hidden" name="[5]" readonly="true"/>
353 <input class="led_color" type="hidden" name="[4]" readonly="true"/>
356 <div class="col-md-2 align-self-center bottom-leds">
357 <input class="led_color" type="hidden" name="[13]" readonly="true"/>
358 <input class="led_color" type="hidden" name="[12]" readonly="true"/>
362 <div class="d-flex justify-content-center">
363 <input class="led_color" type="hidden" name="[8]" readonly="true"/>
364 <input class="led_color" type="hidden" name="[9]" readonly="true"/>
365 <input class="led_color" type="hidden" name="[10]" readonly="true"/>
366 <input class="led_color" type="hidden" name="[11]" readonly="true"/>
369 <div class="col-md-3 offset-md-1">
370 <div class="form-group row">
371 <label class="col-sm-2 col-form-label">Alle</label>
372 <div class="col-sm-10">
373 <input class="led_color" type="text" name="[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]" class="form-control" readonly="true"/>
376 <div class="form-group row">
377 <label class="col-sm-2 col-form-label">Front</label>
378 <div class="col-sm-10">
379 <input class="led_color" type="text" name="[0, 1, 2, 3]" class="form-control" readonly="true"/>
382 <div class="form-group row">
383 <label class="col-sm-2 col-form-label">Aft</label>
384 <div class="col-sm-10">
385 <input class="led_color" type="text" name="[8, 9, 10, 11]" class="form-control" readonly="true"/>
388 <div class="form-group row">
389 <label class="col-sm-2 col-form-label">Top</label>
390 <div class="col-sm-10">
391 <input class="led_color" type="text" name="[4, 5, 6, 7]" class="form-control" readonly="true"/>
394 <div class="form-group row">
395 <label class="col-sm-2 col-form-label">Bottom</label>
396 <div class="col-sm-10">
397 <input class="led_color" type="text" name="[12, 13, 14, 15]" class="form-control" readonly="true"/>
403 <div id="drive" class="tab-pane" role="tabpanel">
404 <div class="cmd_vel_circle"></div>
408 <script src="assets/javascripts/jquery-3.3.1.min.js"></script>
409 <script src="assets/javascripts/popper.min.js"></script>
410 <script src="assets/javascripts/bootstrap.min.js"></script>
411 <script src="assets/javascripts/jquery-ui.min.js"></script>
412 <script src="assets/javascripts/easeljs.min.js"></script>
413 <script src="assets/javascripts/eventemitter2.js"></script>
414 <script src="assets/javascripts/roslib.js"></script>
415 <script src="assets/javascripts/ros2d.js"></script>
416 <script src="assets/javascripts/nav2d.js"></script>
417 <script src="assets/javascripts/keyboardteleop.js"></script>
418 <script src="assets/javascripts/jquery.minicolors.js"></script>
419 <script src="assets/javascripts/vue.js"></script>