www: Add mouse cmd_vel div
[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").append(`
32                                 <div class="alert alert-dismissible alert-success">
33                                         <span data-dismiss="alert">Connected to websocket server.</span>
34                                 </div>
35                                 `);
36                         });
37
38                         ros.on('error', function(error) {
39                                 $("#information").append(`
40                                 <div class="alert alert-dismissible alert-danger">
41                                         <span data-dismiss="alert">Error connecting to websocket server.</span>
42                                 </div>
43                                 `);
44                         });
45
46                         ros.on('close', function() {
47                                 $("#information").append(`
48                                 <div class="alert alert-dismissible alert-info">
49                                         <span data-dismiss="alert">Connection to websocket server closed.</span>
50                                 </div>
51                                 `);
52                         });
53
54                         //tfClient.subscribe('base_link', function(tf) {
55                         //      var now = new Date();
56                         //      $("#pose").text(now.toLocaleTimeString() + ": (" + tf.translation.x + ", " + tf.translation.y + ")");
57
58                         //      robotMarker.x = tf.translation.x;
59                         //      robotMarker.y = -tf.translation.y;
60                         //      robotMarker.rotation = viewer2D.scene.rosQuaternionToGlobalTheta(tf.rotation);
61                         //});
62                         var poseTopic = new ROSLIB.Topic({ros: ros, name: '/robot_pose', messageType: 'geometry_msgs/Pose'});
63                         var sensorTopic = new ROSLIB.Topic({ros: ros, name: '/sensors', messageType: 'wild_thumper/Sensor'});
64                         var batteryTopic = new ROSLIB.Topic({ros: ros, name: '/battery', messageType: 'sensor_msgs/BatteryState'});
65                         var ledStripeTopic = new ROSLIB.Topic({ros: ros, name: '/led_stripe', messageType: 'wild_thumper/LedStripe'});
66                         var cmdVelTopic = new ROSLIB.Topic({ros: ros, name: '/teleop/cmd_vel', messageType: 'geometry_msgs/Twist'});
67
68                         poseTopic.subscribe(function(message) {
69                                 var now = new Date();
70                                 $("#pose").text(now.toLocaleTimeString() + ": (" + message.position.x + ", " + message.position.y + ")");
71                         });
72
73                         sensorTopic.subscribe(function(message) {
74                                 sensordiv = $("#sensors")
75                                 sensordiv.find("input[name=light]").val(message.light);
76                                 sensordiv.find("input[name=temp]").val(message.temp.toFixed(1));
77                                 sensordiv.find("input[name=humidity]").val(message.humidity);
78                                 sensordiv.find("input[name=pressure]").val(message.pressure.toFixed(1));
79                                 sensordiv.find("input[name=co]").val(message.co);
80                         });
81
82                         batteryTopic.subscribe(function(message) {
83                                 powerdiv = $("#power");
84                                 powerdiv.find("input[name=voltage]").val(message.voltage.toFixed(1));
85                                 powerdiv.find("input[name=current]").val(message.current.toFixed(1));
86                         });
87
88                         viewer2D = new ROS2D.Viewer({
89                                 divID: 'map',
90                                 width: 640,
91                                 height: 480,
92                                 background: "#efefef"
93                         });
94                         $('#map')
95                         .bind('mousewheel', function(e) {
96                                 if (e.originalEvent.wheelDelta/120 > 0) {
97                                         viewer2D.scaleToDimensions(10, 10)
98                                 } else {
99                                         viewer2D.scaleToDimensions(5, 5)
100                                 }
101                         })
102                         .mousedown(function() {
103                                 isDragging = true;
104                                 mousePreX = undefined;
105                                 mousePreY = undefined;
106                         })
107                         .mouseup(function() {
108                                 isDragging = false;
109                         })
110                         .mousemove(function(event) {
111                                 if (isDragging) {
112                                         if (mousePreX != undefined && mousePreY != undefined) {
113                                                 var diffX = event.pageX - mousePreX;
114                                                 var diffY = event.pageY - mousePreY;
115                                                 console.log("Moving viewer2D by " + diffX + ", " + diffY);
116                                                 viewer2D.shift(diffX, diffY);
117                                         }
118                                         mousePreX = event.pageX;
119                                         mousePreY = event.pageY;
120                                 }
121                         });
122
123                         // Setup the nav client.
124                         NAV2D.OccupancyGridClientNav({
125                                 ros : ros,
126                                 rootObject : viewer2D.scene,
127                                 viewer : viewer2D,
128                                 serverName : '/move_base'
129                         });
130
131                         // Initialize the teleop.
132                         teleop = new KEYBOARDTELEOP.Teleop({
133                                 ros : ros,
134                                 topic : '/teleop/cmd_vel'
135                         });
136
137                         // Create a UI slider using JQuery UI.
138                         $('#speed-slider').slider({
139                                 range : 'min',
140                                 min : 0.10,
141                                 max : 1.0,
142                                 step : 0.05,
143                                 value : 0.5,
144                                 slide : function(event, ui) {
145                                         // Change the speed label.
146                                         $('#speed-label').html('Speed: ' + ui.value + ' m/s');
147                                         // Scale the speed.
148                                         teleop.scale = (ui.value * 2);
149                                 }
150                         });
151
152                         // Set the initial speed.
153                         $('#speed-label').html('Speed: ' + ($('#speed-slider').slider('value')) + ' m/s');
154                         teleop.scale = ($('#speed-slider').slider('value') * 2);
155
156                         $('.led_color').minicolors({
157                                 control: 'wheel',
158                                 format: 'rgb',
159                                 defaultValue: '#000000',
160                                 change: function(value) {
161                                         var rgb = $(this).minicolors('rgbObject');
162                                         var nums = jQuery.parseJSON($(this).prop("name"));
163                                         var msg = new ROSLIB.Message({
164                                                 leds: []
165                                         });
166                                         jQuery.each(nums, function(i, num) {
167                                                 msg["leds"].push({
168                                                         num: num,
169                                                         red: parseInt(rgb.r*127/255),
170                                                         green: parseInt(rgb.g*127/255),
171                                                         blue: parseInt(rgb.b*127/255)
172                                                 })
173                                         });
174                                         ledStripeTopic.publish(msg);
175                                 }
176                         });
177
178                         function setSpeed(trans, rot) {
179                                 var msg = new ROSLIB.Message({
180                                         linear: {
181                                                 x : trans,
182                                                 y : 0,
183                                                 z : 0
184                                         },
185                                         angular: {
186                                                 x : 0,
187                                                 y : 0,
188                                                 z : rot
189                                         },
190                                 });
191                                 cmdVelTopic.publish(msg);
192                         }
193
194                         $('.cmd_vel_circle')
195                         .bind('mousedown touchstart', function(e) {
196                                 isDragging = true;
197                         })
198                         .bind('mouseup touchend mouseleave', function(e) {
199                                 isDragging = false;
200                                 setSpeed(0, 0);
201                         })
202                         .bind('mousemove touchmove', function(e) {
203                                 if (isDragging) {
204                                         // absolute click position
205                                         var X,Y;
206                                         if (e.originalEvent.touches) {
207                                                 X = e.originalEvent.touches[0].pageX;
208                                                 Y = e.originalEvent.touches[0].pageY;
209                                         } else {
210                                                 X = e.pageX;
211                                                 Y = e.pageY;
212                                         }
213                                         // relative click position
214                                         var Xrel = X - this.offsetLeft - $(this).width()/2; 
215                                         var Yrel = Y - this.offsetTop - $(this).height()/2; 
216                                         // scale to -1..+1
217                                         var trans = -Yrel / ($(this).height()/2);
218                                         var rot = -Xrel / ($(this).width()/2);
219                                         setSpeed(trans, rot*3);
220                                 }
221                         });
222                 }
223                 </script>
224                 <title>Wild Thumper control</title>
225         </head>
226         <body onload="init()">
227                 <div class="container-fluid">
228                         <div id="information">
229                         </div>
230
231                         <nav class="navbar navbar-expand-lg navbar-light bg-light">
232                                 <a class="navbar-brand" href="#">Wild Thumper</a>
233                                 <ul class="nav nav-tabs" role="tablist">
234                                         <li class="nav-item">
235                                                 <a class="nav-link active" href="#data" data-toggle="tab" role="tab">Data</a>
236                                         </li>
237                                         <li class="nav-item">
238                                                 <a class="nav-link" href="#navigation" data-toggle="tab" role="tab">Navigation</a>
239                                         </li>
240                                         <li class="nav-item">
241                                                 <a class="nav-link" href="#lights" data-toggle="tab" role="tab">Lights</a>
242                                         </li>
243                                         <li class="nav-item">
244                                                 <a class="nav-link" href="#drive" data-toggle="tab" role="tab">Drive</a>
245                                         </li>
246                                 </ul>
247                         </nav>
248                         <div class="tab-content">
249                                 <div id="data" class="tab-pane active" role="tabpanel">
250                                         <div class="row">
251                                                 <div id="power" class="col-auto">
252                                                         <h4>Power</h4>
253                                                         <label>Voltage:</label>
254                                                         <div class="input-group">
255                                                                 <input type=text name="voltage" class="form-control" readonly>
256                                                                 <div class="input-group-append">
257                                                                         <span class="input-group-text">V</span>
258                                                                 </div>
259                                                         </div>
260                                                         <label>Current:</label>
261                                                         <div class="input-group">
262                                                                 <input type=text name="current" class="form-control" readonly>
263                                                                 <div class="input-group-append">
264                                                                         <span class="input-group-text">A</span>
265                                                                 </div>
266                                                         </div>
267                                                 </div>
268                                                 <div id="sensors" class="col-auto">
269                                                         <h4>Sensors</h4>
270                                                         <label>Light:</label>
271                                                         <div class="input-group">
272                                                                 <input type=text name="light" class="form-control" readonly>
273                                                                 <div class="input-group-append">
274                                                                         <span class="input-group-text">lx</span>
275                                                                 </div>
276                                                         </div>
277                                                         <label>Temperature:</label>
278                                                         <div class="input-group">
279                                                                 <input type=text name="temp" class="form-control" readonly>
280                                                                 <div class="input-group-append">
281                                                                         <span class="input-group-text">&#x2103</span>
282                                                                 </div>
283                                                         </div>
284                                                         <label>Humidity:</label>
285                                                         <div class="input-group">
286                                                                 <input type=text name="humidity" class="form-control" readonly>
287                                                                 <div class="input-group-append">
288                                                                         <span class="input-group-text">%</span>
289                                                                 </div>
290                                                         </div>
291                                                         <label>Pressure:</label>
292                                                         <div class="input-group">
293                                                                 <input type=text name="pressure" class="form-control" readonly>
294                                                                 <div class="input-group-append">
295                                                                         <span class="input-group-text">kPa</span>
296                                                                 </div>
297                                                         </div>
298                                                         <label>CO:</label>
299                                                         <input type=text name="co" class="form-control" readonly>
300                                                 </div>
301                                         </div>
302                                 </div>
303                                 <div id="navigation" class="tab-pane" role="tabpanel">
304                                         <div id="pose"></div>
305                                         <div id="map"></div>
306                                         <div id="speed-label"></div>
307                                         <div id="speed-slider"></div>
308                                 </div>
309                                 <div id="lights" class="tab-pane" role="tabpanel">
310                                         <div class="row">
311                                                 <div class="col-md-2 offset-md-1" >
312                                                         <div class="d-flex justify-content-center">
313                                                                 <input class="led_color" type="hidden" name="[0]" readonly="true"/>
314                                                                 <input class="led_color" type="hidden" name="[1]" readonly="true"/>
315                                                                 <input class="led_color" type="hidden" name="[2]" readonly="true"/>
316                                                                 <input class="led_color" type="hidden" name="[3]" readonly="true"/>
317                                                         </div>
318                                                         <div>
319                                                                 <div class="row wt-icon">
320                                                                         <div class="col-md-2 align-self-center bottom-leds">
321                                                                                 <input class="led_color" type="hidden" name="[14]" readonly="true"/>
322                                                                                 <input class="led_color" type="hidden" name="[15]" readonly="true"/>
323                                                                         </div>
324                                                                         <div class="col-md-8">
325                                                                                 <div class="d-flex justify-content-center top-leds">
326                                                                                         <input class="led_color" type="hidden" name="[7]" readonly="true"/>
327                                                                                         <input class="led_color" type="hidden" name="[6]" readonly="true"/>
328                                                                                         <input class="led_color" type="hidden" name="[5]" readonly="true"/>
329                                                                                         <input class="led_color" type="hidden" name="[4]" readonly="true"/>
330                                                                                 </div>
331                                                                         </div>
332                                                                         <div class="col-md-2 align-self-center bottom-leds">
333                                                                                 <input class="led_color" type="hidden" name="[13]" readonly="true"/>
334                                                                                 <input class="led_color" type="hidden" name="[12]" readonly="true"/>
335                                                                         </div>
336                                                                 </div>
337                                                         </div>
338                                                         <div class="d-flex justify-content-center">
339                                                                 <input class="led_color" type="hidden" name="[8]" readonly="true"/>
340                                                                 <input class="led_color" type="hidden" name="[9]" readonly="true"/>
341                                                                 <input class="led_color" type="hidden" name="[10]" readonly="true"/>
342                                                                 <input class="led_color" type="hidden" name="[11]" readonly="true"/>
343                                                         </div>
344                                                 </div>
345                                                 <div class="col-md-3 offset-md-1">
346                                                         <div class="form-group row">
347                                                                 <label class="col-sm-2 col-form-label">Alle</label>
348                                                                 <div class="col-sm-10">
349                                                                         <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"/>
350                                                                 </div>
351                                                         </div>
352                                                         <div class="form-group row">
353                                                                 <label class="col-sm-2 col-form-label">Front</label>
354                                                                 <div class="col-sm-10">
355                                                                         <input class="led_color" type="text" name="[0, 1, 2, 3]" class="form-control" readonly="true"/>
356                                                                 </div>
357                                                         </div>
358                                                         <div class="form-group row">
359                                                                 <label class="col-sm-2 col-form-label">Aft</label>
360                                                                 <div class="col-sm-10">
361                                                                         <input class="led_color" type="text" name="[8, 9, 10, 11]" class="form-control readonly="true""/>
362                                                                 </div>
363                                                         </div>
364                                                         <div class="form-group row">
365                                                                 <label class="col-sm-2 col-form-label">Top</label>
366                                                                 <div class="col-sm-10">
367                                                                         <input class="led_color" type="text" name="[4, 5, 6, 7]" class="form-control" readonly="true"/>
368                                                                 </div>
369                                                         </div>
370                                                         <div class="form-group row">
371                                                                 <label class="col-sm-2 col-form-label">Bottom</label>
372                                                                 <div class="col-sm-10">
373                                                                         <input class="led_color" type="text" name="[12, 13, 14, 15]" class="form-control" readonly="true"/>
374                                                                 </div>
375                                                         </div>
376                                                 </div>
377                                         </div>
378                                 </div>
379                                 <div id="drive" class="tab-pane" role="tabpanel">
380                                         <div class="cmd_vel_circle"></div>
381                                 </div>
382                         </div>
383                 </div>
384                 <script src="assets/javascripts/jquery-3.3.1.min.js"></script>
385                 <script src="assets/javascripts/popper.min.js"></script>
386                 <script src="assets/javascripts/bootstrap.min.js"></script>
387                 <script src="assets/javascripts/jquery-ui.min.js"></script>
388                 <script src="assets/javascripts/easeljs.min.js"></script>
389                 <script src="assets/javascripts/eventemitter2.js"></script>
390                 <script src="assets/javascripts/roslib.js"></script>
391                 <script src="assets/javascripts/ros2d.js"></script>
392                 <script src="assets/javascripts/nav2d.js"></script>
393                 <script src="assets/javascripts/keyboardteleop.js"></script>
394                 <script src="assets/javascripts/jquery.minicolors.js"></script>
395         </body>
396 </html>