www: fix typo
[ros_wild_thumper.git] / www / index.html
1 <!doctype html>
2 <html>
3         <head>
4                 <meta charset="utf-8" />
5
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">
9
10                 <style>
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;}
15                 .cmd_vel_circle {
16                         height: 250px;
17                         width: 250px;
18                         background-color: #bbb;
19                         border-radius: 50%;
20                         display: inline-block;
21                 }
22                 </style>
23
24                 <script type="text/javascript">
25                 function init() {
26                         var ros = new ROSLIB.Ros();
27                         ros.connect('ws://wildthumper:9090');
28                         var isDragging = false;
29
30                         ros.on('connection', function() {
31                                 information.alerts.push({message: "Connected to websocket server.", success: true});
32                         });
33
34                         ros.on('error', function(error) {
35                                 information.alerts.push({message: "Error connecting to websocket server.", danger: true});
36                         });
37
38                         ros.on('close', function() {
39                                 information.alerts.push({message: "Connection to websocket server closed.", info: true});
40                         });
41
42                         //tfClient.subscribe('base_link', function(tf) {
43                         //      var now = new Date();
44                         //      $("#pose").text(now.toLocaleTimeString() + ": (" + tf.translation.x + ", " + tf.translation.y + ")");
45
46                         //      robotMarker.x = tf.translation.x;
47                         //      robotMarker.y = -tf.translation.y;
48                         //      robotMarker.rotation = viewer2D.scene.rosQuaternionToGlobalTheta(tf.rotation);
49                         //});
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'});
55
56                         poseTopic.subscribe(function(message) {
57                                 var now = new Date();
58                                 $("#pose").text(now.toLocaleTimeString() + ": (" + message.position.x + ", " + message.position.y + ")");
59                         });
60
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;
67                         });
68
69                         batteryTopic.subscribe(function(message) {
70                                 power.voltage = message.voltage.toFixed(1);
71                                 power.current = message.current.toFixed(1);
72                         });
73
74                         viewer2D = new ROS2D.Viewer({
75                                 divID: 'map',
76                                 width: 640,
77                                 height: 480,
78                                 background: "#efefef"
79                         });
80                         $('#map')
81                         .bind('mousewheel', function(e) {
82                                 if (e.originalEvent.wheelDelta/120 > 0) {
83                                         viewer2D.scaleToDimensions(10, 10)
84                                 } else {
85                                         viewer2D.scaleToDimensions(5, 5)
86                                 }
87                         })
88                         .mousedown(function() {
89                                 isDragging = true;
90                                 mousePreX = undefined;
91                                 mousePreY = undefined;
92                         })
93                         .mouseup(function() {
94                                 isDragging = false;
95                         })
96                         .mousemove(function(event) {
97                                 if (isDragging) {
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);
103                                         }
104                                         mousePreX = event.pageX;
105                                         mousePreY = event.pageY;
106                                 }
107                         });
108
109                         // Setup the nav client.
110                         NAV2D.OccupancyGridClientNav({
111                                 ros : ros,
112                                 rootObject : viewer2D.scene,
113                                 viewer : viewer2D,
114                                 serverName : '/move_base'
115                         });
116
117                         // Initialize the teleop.
118                         teleop = new KEYBOARDTELEOP.Teleop({
119                                 ros : ros,
120                                 topic : '/teleop/cmd_vel'
121                         });
122
123                         // Create a UI slider using JQuery UI.
124                         $('#speed-slider').slider({
125                                 range : 'min',
126                                 min : 0.10,
127                                 max : 1.0,
128                                 step : 0.05,
129                                 value : 0.5,
130                                 slide : function(event, ui) {
131                                         // Change the speed label.
132                                         speed_label.speed = ui.value;
133                                         // Scale the speed.
134                                         teleop.scale = (ui.value * 2);
135                                 }
136                         });
137
138                         // Set the initial speed.
139                         teleop.scale = ($('#speed-slider').slider('value') * 2);
140
141                         $('.led_color').minicolors({
142                                 control: 'wheel',
143                                 format: 'rgb',
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({
149                                                 leds: []
150                                         });
151                                         jQuery.each(nums, function(i, num) {
152                                                 msg["leds"].push({
153                                                         num: num,
154                                                         red: parseInt(rgb.r*127/255),
155                                                         green: parseInt(rgb.g*127/255),
156                                                         blue: parseInt(rgb.b*127/255)
157                                                 })
158                                         });
159                                         ledStripeTopic.publish(msg);
160                                 }
161                         });
162
163                         function setSpeed(trans, rot) {
164                                 var msg = new ROSLIB.Message({
165                                         linear: {
166                                                 x : trans,
167                                                 y : 0,
168                                                 z : 0
169                                         },
170                                         angular: {
171                                                 x : 0,
172                                                 y : 0,
173                                                 z : rot
174                                         },
175                                 });
176                                 cmdVelTopic.publish(msg);
177                         }
178
179                         $('.cmd_vel_circle')
180                         .bind('mousedown touchstart', function(e) {
181                                 isDragging = true;
182                         })
183                         .bind('mouseup touchend mouseleave', function(e) {
184                                 isDragging = false;
185                                 setSpeed(0, 0);
186                         })
187                         .bind('mousemove touchmove', function(e) {
188                                 if (isDragging) {
189                                         // absolute click position
190                                         var X,Y;
191                                         if (e.originalEvent.touches) {
192                                                 X = e.originalEvent.touches[0].pageX;
193                                                 Y = e.originalEvent.touches[0].pageY;
194                                         } else {
195                                                 X = e.pageX;
196                                                 Y = e.pageY;
197                                         }
198                                         // relative click position
199                                         var Xrel = X - this.offsetLeft - $(this).width()/2; 
200                                         var Yrel = Y - this.offsetTop - $(this).height()/2; 
201                                         // scale to -1..+1
202                                         var trans = -Yrel / ($(this).height()/2);
203                                         var rot = -Xrel / ($(this).width()/2);
204                                         setSpeed(trans, rot*3);
205                                 }
206                         });
207
208                         information = new Vue({
209                                 el: '#information',
210                                 data: {
211                                         alerts: [],
212                                 },
213                                 methods: {
214                                         classObject: function(id) {
215                                                 return {
216                                                         "alert-success": this.alerts[id].success,
217                                                         "alert-danger": this.alerts[id].danger,
218                                                         "alert-info": this.alerts[id].info
219                                                 }
220                                         }
221                                 }
222                         })
223
224                         sensors = new Vue({
225                                 el: '#sensors',
226                                 data: {light: '', temp: '', humidity: '', pressure: '', co: ''}
227                         })
228
229                         power = new Vue({
230                                 el: '#power',
231                                 data: {
232                                         voltage: '',
233                                         current: '',
234                                 }
235                         })
236
237                         speed_label = new Vue({
238                                 el: '#speed-label',
239                                 data: {
240                                         speed: $('#speed-slider').slider('value'),
241                                 }
242                         })
243                 }
244                 </script>
245                 <title>Wild Thumper control</title>
246         </head>
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>
252                                 </div>
253                         </div>
254
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>
260                                         </li>
261                                         <li class="nav-item">
262                                                 <a class="nav-link" href="#navigation" data-toggle="tab" role="tab">Navigation</a>
263                                         </li>
264                                         <li class="nav-item">
265                                                 <a class="nav-link" href="#lights" data-toggle="tab" role="tab">Lights</a>
266                                         </li>
267                                         <li class="nav-item">
268                                                 <a class="nav-link" href="#drive" data-toggle="tab" role="tab">Drive</a>
269                                         </li>
270                                 </ul>
271                         </nav>
272                         <div class="tab-content">
273                                 <div id="data" class="tab-pane active" role="tabpanel">
274                                         <div class="row">
275                                                 <div id="power" class="col-auto">
276                                                         <h4>Power</h4>
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>
282                                                                 </div>
283                                                         </div>
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>
289                                                                 </div>
290                                                         </div>
291                                                 </div>
292                                                 <div id="sensors" class="col-auto">
293                                                         <h4>Sensors</h4>
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>
299                                                                 </div>
300                                                         </div>
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">&#x2103</span>
306                                                                 </div>
307                                                         </div>
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>
313                                                                 </div>
314                                                         </div>
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>
320                                                                 </div>
321                                                         </div>
322                                                         <label>CO:</label>
323                                                         <input type=text name="co" class="form-control" v-model="co" readonly>
324                                                 </div>
325                                         </div>
326                                 </div>
327                                 <div id="navigation" class="tab-pane" role="tabpanel">
328                                         <div id="pose"></div>
329                                         <div id="map"></div>
330                                         <div id="speed-label">Speed: {{speed}} m/s</div>
331                                         <div id="speed-slider"></div>
332                                 </div>
333                                 <div id="lights" class="tab-pane" role="tabpanel">
334                                         <div class="row">
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"/>
341                                                         </div>
342                                                         <div>
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"/>
347                                                                         </div>
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"/>
354                                                                                 </div>
355                                                                         </div>
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"/>
359                                                                         </div>
360                                                                 </div>
361                                                         </div>
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"/>
367                                                         </div>
368                                                 </div>
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"/>
374                                                                 </div>
375                                                         </div>
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"/>
380                                                                 </div>
381                                                         </div>
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"/>
386                                                                 </div>
387                                                         </div>
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"/>
392                                                                 </div>
393                                                         </div>
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"/>
398                                                                 </div>
399                                                         </div>
400                                                 </div>
401                                         </div>
402                                 </div>
403                                 <div id="drive" class="tab-pane" role="tabpanel">
404                                         <div class="cmd_vel_circle"></div>
405                                 </div>
406                         </div>
407                 </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>
420         </body>
421 </html>