www: speed control
[ros_wild_thumper.git] / www / assets / javascripts / application.js
1 function init() {
2         var ros = new ROSLIB.Ros();
3         connect();
4         var isDragging = false;
5
6         function connect() {
7                 ros.connect('ws://wildthumper:9090');
8         }
9
10         ros.on('connection', function() {
11                 information.alerts.push({message: "Connected to websocket server.", success: true});
12         });
13
14         ros.on('error', function(error) {
15                 information.alerts.push({message: "Error connecting to websocket server.", danger: true});
16         });
17
18         ros.on('close', function() {
19                 information.alerts.push({message: "Connection to websocket server closed.", info: true});
20                 setTimeout(function() {
21                         connect();
22                 }, 2000);
23         });
24
25         //tfClient.subscribe('base_link', function(tf) {
26         //      var now = new Date();
27         //      $("#pose").text(now.toLocaleTimeString() + ": (" + tf.translation.x + ", " + tf.translation.y + ")");
28
29         //      robotMarker.x = tf.translation.x;
30         //      robotMarker.y = -tf.translation.y;
31         //      robotMarker.rotation = viewer2D.scene.rosQuaternionToGlobalTheta(tf.rotation);
32         //});
33         var poseTopic = new ROSLIB.Topic({ros: ros, name: '/robot_pose', messageType: 'geometry_msgs/Pose'});
34         var sensorTopic = new ROSLIB.Topic({ros: ros, name: '/sensors', messageType: 'wild_thumper/Sensor'});
35         var batteryTopic = new ROSLIB.Topic({ros: ros, name: '/battery', messageType: 'sensor_msgs/BatteryState'});
36         var ledStripeTopic = new ROSLIB.Topic({ros: ros, name: '/led_stripe', messageType: 'wild_thumper/LedStripe'});
37         var cmdVelTopic = new ROSLIB.Topic({ros: ros, name: '/teleop/cmd_vel', messageType: 'geometry_msgs/Twist'});
38
39         poseTopic.subscribe(function(message) {
40                 var now = new Date();
41                 $("#pose").text(now.toLocaleTimeString() + ": (" + message.position.x + ", " + message.position.y + ")");
42         });
43
44         sensorTopic.subscribe(function(message) {
45                 sensors.light = message.light;
46                 sensors.temp = message.temp.toFixed(1);
47                 sensors.humidity = message.humidity;
48                 sensors.pressure = message.pressure.toFixed(1);
49                 sensors.co = message.co;
50         });
51
52         batteryTopic.subscribe(function(message) {
53                 power.voltage = message.voltage.toFixed(1);
54                 power.current = message.current.toFixed(1);
55         });
56
57         viewer2D = new ROS2D.Viewer({
58                 divID: 'map',
59                 width: 640,
60                 height: 480,
61                 background: "#efefef"
62         });
63         $('#map')
64         .bind('mousewheel', function(e) {
65                 if (e.originalEvent.wheelDelta/120 > 0) {
66                         viewer2D.scaleToDimensions(10, 10)
67                 } else {
68                         viewer2D.scaleToDimensions(5, 5)
69                 }
70         })
71         .mousedown(function() {
72                 isDragging = true;
73                 mousePreX = undefined;
74                 mousePreY = undefined;
75         })
76         .mouseup(function() {
77                 isDragging = false;
78         })
79         .mousemove(function(event) {
80                 if (isDragging) {
81                         if (mousePreX != undefined && mousePreY != undefined) {
82                                 var diffX = event.pageX - mousePreX;
83                                 var diffY = event.pageY - mousePreY;
84                                 console.log("Moving viewer2D by " + diffX + ", " + diffY);
85                                 viewer2D.shift(diffX, diffY);
86                         }
87                         mousePreX = event.pageX;
88                         mousePreY = event.pageY;
89                 }
90         });
91
92         // Setup the nav client.
93         NAV2D.OccupancyGridClientNav({
94                 ros : ros,
95                 rootObject : viewer2D.scene,
96                 viewer : viewer2D,
97                 serverName : '/move_base'
98         });
99
100         // Initialize the teleop.
101         teleop = new KEYBOARDTELEOP.Teleop({
102                 ros : ros,
103                 topic : '/teleop/cmd_vel'
104         });
105
106         // Create a UI slider using JQuery UI.
107         $('#speed-slider').slider({
108                 range : 'min',
109                 min : 0.10,
110                 max : 1.0,
111                 step : 0.05,
112                 value : 0.5,
113                 slide : function(event, ui) {
114                         // Change the speed label.
115                         speed_label.speed = ui.value;
116                         // Scale the speed.
117                         teleop.scale = (ui.value * 2);
118                 }
119         });
120
121         // Set the initial speed.
122         teleop.scale = ($('#speed-slider').slider('value') * 2);
123
124         new Vue({
125                 el: '#lights',
126                 data: {
127                         front_row: ["[0]", "[1]", "[2]", "[3]"],
128                         top_row: ["[7]", "[6]", "[5]", "[4]"],
129                         aft_row: ["[8]", "[9]", "[10]", "[11]"],
130                         bottom_left_row: ["[14]", "[15]"],
131                         bottom_right_row: ["[13]", "[12]"],
132                 }
133         })
134         $('.led_color').minicolors({
135                 control: 'wheel',
136                 format: 'rgb',
137                 defaultValue: '#000000',
138                 change: function(value) {
139                         var rgb = $(this).minicolors('rgbObject');
140                         var nums = jQuery.parseJSON($(this).prop("name"));
141                         var msg = new ROSLIB.Message({
142                                 leds: []
143                         });
144                         jQuery.each(nums, function(i, num) {
145                                 msg["leds"].push({
146                                         num: num,
147                                         red: parseInt(rgb.r*127/255),
148                                         green: parseInt(rgb.g*127/255),
149                                         blue: parseInt(rgb.b*127/255)
150                                 })
151                         });
152                         ledStripeTopic.publish(msg);
153                 }
154         });
155
156         function setSpeed(trans, rot) {
157                 var msg = new ROSLIB.Message({
158                         linear: {
159                                 x : trans,
160                                 y : 0,
161                                 z : 0
162                         },
163                         angular: {
164                                 x : 0,
165                                 y : 0,
166                                 z : rot
167                         },
168                 });
169                 cmdVelTopic.publish(msg);
170         }
171
172         $('.cmd_vel_circle')
173         .bind('mousedown touchstart', function(e) {
174                 isDragging = true;
175         })
176         .bind('mouseup touchend mouseleave', function(e) {
177                 isDragging = false;
178                 setSpeed(0, 0);
179         })
180         .bind('mousemove touchmove', function(e) {
181                 if (isDragging) {
182                         // absolute click position
183                         var X,Y;
184                         if (e.originalEvent.touches) {
185                                 X = e.originalEvent.touches[0].pageX;
186                                 Y = e.originalEvent.touches[0].pageY;
187                         } else {
188                                 X = e.pageX;
189                                 Y = e.pageY;
190                         }
191                         // relative click position
192                         var Xrel = X - this.getBoundingClientRect().left - $(this).width()/2;
193                         var Yrel = Y - this.getBoundingClientRect().top - $(this).height()/2;
194                         // scale to -1..+1
195                         var trans = -Yrel / ($(this).height()/2);
196                         var rot = -Xrel / ($(this).width()/2);
197                         setSpeed(trans*$("#scale_trans").val(), rot*$("#scale_rot").val());
198                 }
199         });
200
201         information = new Vue({
202                 el: '#information',
203                 data: {
204                         alerts: [],
205                 },
206                 methods: {
207                         classObject: function(id) {
208                                 return {
209                                         "alert-success": this.alerts[id].success,
210                                         "alert-danger": this.alerts[id].danger,
211                                         "alert-info": this.alerts[id].info
212                                 }
213                         }
214                 }
215         })
216
217         sensors = new Vue({
218                 el: '#sensors',
219                 data: {light: '', temp: '', humidity: '', pressure: '', co: ''}
220         })
221
222         power = new Vue({
223                 el: '#power',
224                 data: {
225                         voltage: '',
226                         current: '',
227                 }
228         })
229
230         speed_label = new Vue({
231                 el: '#speed-label',
232                 data: {
233                         speed: $('#speed-slider').slider('value'),
234                 }
235         })
236
237         $(".imagelink").on('click',function(){
238                 // reload
239                 $("img").attr("src", $("img").attr("src"))
240         });
241
242         $("input[type='number']").spinner();
243 }
244
245 Vue.component('input-value', {
246         template: '#input-value-template',
247         props: ['value', 'label', 'unit']
248 })
249
250 Vue.component('input-led', {
251         template: '#input-led-template',
252         props: ['name', 'label']
253 })