<style>
.minicolors-theme-default.minicolors { margin: 5px; }
+ .bottom-leds > .minicolors-theme-default.minicolors { margin: 5px 0; }
+ .top-leds > .minicolors-theme-default.minicolors { margin-top: 70px; }
+ .wt-icon {background: url('assets/images/wt_top.png'); background-size: cover; background-size: 100%; background-repeat: no-repeat; background-position: center; height: 260px;}
+ .cmd_vel_circle {
+ height: 250px;
+ width: 250px;
+ background-color: #bbb;
+ border-radius: 50%;
+ display: inline-block;
+ }
</style>
<script type="text/javascript">
var isDragging = false;
ros.on('connection', function() {
- $("#information").append(`
- <div class="alert alert-dismissible alert-success">
- <span data-dismiss="alert">Connected to websocket server.</span>
- </div>
- `);
+ information.alerts.push({message: "Connected to websocket server.", success: true});
});
ros.on('error', function(error) {
- $("#information").append(`
- <div class="alert alert-dismissible alert-danger">
- <span data-dismiss="alert">Error connecting to websocket server.</span>
- </div>
- `);
+ information.alerts.push({message: "Error connecting to websocket server.", danger: true});
});
ros.on('close', function() {
- $("#information").append(`
- <div class="alert alert-dismissible alert-info">
- <span data-dismiss="alert">Connection to websocket server closed.</span>
- </div>
- `);
+ information.alerts.push({message: "Connection to websocket server closed.", info: true});
});
//tfClient.subscribe('base_link', function(tf) {
var sensorTopic = new ROSLIB.Topic({ros: ros, name: '/sensors', messageType: 'wild_thumper/Sensor'});
var batteryTopic = new ROSLIB.Topic({ros: ros, name: '/battery', messageType: 'sensor_msgs/BatteryState'});
var ledStripeTopic = new ROSLIB.Topic({ros: ros, name: '/led_stripe', messageType: 'wild_thumper/LedStripe'});
+ var cmdVelTopic = new ROSLIB.Topic({ros: ros, name: '/teleop/cmd_vel', messageType: 'geometry_msgs/Twist'});
poseTopic.subscribe(function(message) {
var now = new Date();
});
sensorTopic.subscribe(function(message) {
- sensordiv = $("#sensors")
- sensordiv.find("input[name=light]").val(message.light);
- sensordiv.find("input[name=temp]").val(message.temp.toFixed(1));
- sensordiv.find("input[name=humidity]").val(message.humidity);
- sensordiv.find("input[name=pressure]").val(message.pressure.toFixed(1));
- sensordiv.find("input[name=co]").val(message.co);
+ sensors.light = message.light;
+ sensors.temp = message.temp.toFixed(1);
+ sensors.humidity = message.humidity;
+ sensors.pressure = message.pressure.toFixed(1);
+ sensors.co = message.co;
});
batteryTopic.subscribe(function(message) {
- powerdiv = $("#power");
- powerdiv.find("input[name=voltage]").val(message.voltage.toFixed(1));
- powerdiv.find("input[name=current]").val(message.current.toFixed(1));
+ power.voltage = message.voltage.toFixed(1);
+ power.current = message.current.toFixed(1);
});
viewer2D = new ROS2D.Viewer({
});
// Initialize the teleop.
- var teleop = new KEYBOARDTELEOP.Teleop({
+ teleop = new KEYBOARDTELEOP.Teleop({
ros : ros,
- topic : '/cmd_vel'
+ topic : '/teleop/cmd_vel'
});
// Create a UI slider using JQuery UI.
$('#speed-slider').slider({
range : 'min',
- min : 0,
- max : 100,
- value : 50,
+ min : 0.10,
+ max : 1.0,
+ step : 0.05,
+ value : 0.5,
slide : function(event, ui) {
// Change the speed label.
- $('#speed-label').html('Speed: ' + ui.value + '%');
+ speed_label.speed = ui.value;
// Scale the speed.
- teleop.scale = (ui.value / 100.0);
+ teleop.scale = (ui.value * 2);
}
});
// Set the initial speed.
- $('#speed-label').html('Speed: ' + ($('#speed-slider').slider('value')) + '%');
- teleop.scale = ($('#speed-slider').slider('value') / 100.0);
+ teleop.scale = ($('#speed-slider').slider('value') * 2);
$('.led_color').minicolors({
control: 'wheel',
defaultValue: '#000000',
change: function(value) {
var rgb = $(this).minicolors('rgbObject');
- var num = $(this).prop("name");
+ var nums = jQuery.parseJSON($(this).prop("name"));
var msg = new ROSLIB.Message({
- leds: [{
- num: parseInt(num),
+ leds: []
+ });
+ jQuery.each(nums, function(i, num) {
+ msg["leds"].push({
+ num: num,
red: parseInt(rgb.r*127/255),
green: parseInt(rgb.g*127/255),
blue: parseInt(rgb.b*127/255)
- }]
+ })
});
ledStripeTopic.publish(msg);
}
});
+
+ function setSpeed(trans, rot) {
+ var msg = new ROSLIB.Message({
+ linear: {
+ x : trans,
+ y : 0,
+ z : 0
+ },
+ angular: {
+ x : 0,
+ y : 0,
+ z : rot
+ },
+ });
+ cmdVelTopic.publish(msg);
+ }
+
+ $('.cmd_vel_circle')
+ .bind('mousedown touchstart', function(e) {
+ isDragging = true;
+ })
+ .bind('mouseup touchend mouseleave', function(e) {
+ isDragging = false;
+ setSpeed(0, 0);
+ })
+ .bind('mousemove touchmove', function(e) {
+ if (isDragging) {
+ // absolute click position
+ var X,Y;
+ if (e.originalEvent.touches) {
+ X = e.originalEvent.touches[0].pageX;
+ Y = e.originalEvent.touches[0].pageY;
+ } else {
+ X = e.pageX;
+ Y = e.pageY;
+ }
+ // relative click position
+ var Xrel = X - this.offsetLeft - $(this).width()/2;
+ var Yrel = Y - this.offsetTop - $(this).height()/2;
+ // scale to -1..+1
+ var trans = -Yrel / ($(this).height()/2);
+ var rot = -Xrel / ($(this).width()/2);
+ setSpeed(trans, rot*3);
+ }
+ });
+
+ information = new Vue({
+ el: '#information',
+ data: {
+ alerts: [],
+ },
+ methods: {
+ classObject: function(id) {
+ return {
+ "alert-success": this.alerts[id].success,
+ "alert-danger": this.alerts[id].danger,
+ "alert-info": this.alerts[id].info
+ }
+ }
+ }
+ })
+
+ sensors = new Vue({
+ el: '#sensors',
+ data: {light: '', temp: '', humidity: '', pressure: '', co: ''}
+ })
+
+ power = new Vue({
+ el: '#power',
+ data: {
+ voltage: '',
+ current: '',
+ }
+ })
+
+ speed_label = new Vue({
+ el: '#speed-label',
+ data: {
+ speed: $('#speed-slider').slider('value'),
+ }
+ })
}
</script>
<title>Wild Thumper control</title>
<body onload="init()">
<div class="container-fluid">
<div id="information">
+ <div v-for="(alert, id) in alerts" class="alert alert-dismissible}" v-bind:class="classObject(id)">
+ <span data-dismiss="alert">{{alert.message}}</span>
+ </div>
</div>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<li class="nav-item">
<a class="nav-link" href="#lights" data-toggle="tab" role="tab">Lights</a>
</li>
+ <li class="nav-item">
+ <a class="nav-link" href="#drive" data-toggle="tab" role="tab">Drive</a>
+ </li>
</ul>
</nav>
<div class="tab-content">
<h4>Power</h4>
<label>Voltage:</label>
<div class="input-group">
- <input type=text name="voltage" class="form-control" readonly>
+ <input type=text name="voltage" class="form-control" v-model="voltage" readonly>
<div class="input-group-append">
<span class="input-group-text">V</span>
</div>
</div>
<label>Current:</label>
<div class="input-group">
- <input type=text name="current" class="form-control" readonly>
+ <input type=text name="current" class="form-control" v-model="current" readonly>
<div class="input-group-append">
<span class="input-group-text">A</span>
</div>
<h4>Sensors</h4>
<label>Light:</label>
<div class="input-group">
- <input type=text name="light" class="form-control" readonly>
+ <input type=text name="light" class="form-control" v-model="light" readonly>
<div class="input-group-append">
<span class="input-group-text">lx</span>
</div>
</div>
<label>Temperature:</label>
<div class="input-group">
- <input type=text name="temp" class="form-control" readonly>
+ <input type=text name="temp" class="form-control" v-model="temp" readonly>
<div class="input-group-append">
<span class="input-group-text">℃</span>
</div>
</div>
<label>Humidity:</label>
<div class="input-group">
- <input type=text name="humidity" class="form-control" readonly>
+ <input type=text name="humidity" class="form-control" v-model="humidity" readonly>
<div class="input-group-append">
<span class="input-group-text">%</span>
</div>
</div>
<label>Pressure:</label>
<div class="input-group">
- <input type=text name="pressure" class="form-control" readonly>
+ <input type=text name="pressure" class="form-control" v-model="pressure" readonly>
<div class="input-group-append">
<span class="input-group-text">kPa</span>
</div>
</div>
<label>CO:</label>
- <input type=text name="co" class="form-control" readonly>
+ <input type=text name="co" class="form-control" v-model="co" readonly>
</div>
</div>
</div>
<div id="navigation" class="tab-pane" role="tabpanel">
<div id="pose"></div>
<div id="map"></div>
- <div id="speed-label"></div>
+ <div id="speed-label">Speed: {{speed}} m/s</div>
<div id="speed-slider"></div>
</div>
<div id="lights" class="tab-pane" role="tabpanel">
- <div class="row d-flex align-items-center">
- <div class="col-md-1">
- <div class="float-right align-middle">
- <input class="led_color" type="hidden" name="15"/>
- <input class="led_color" type="hidden" name="14"/>
- </div>
- </div>
- <div class="col-md-2" >
+ <div class="row">
+ <div class="col-md-2 offset-md-1" >
<div class="d-flex justify-content-center">
- <input class="led_color" type="hidden" name="0"/>
- <input class="led_color" type="hidden" name="1"/>
- <input class="led_color" type="hidden" name="2"/>
- <input class="led_color" type="hidden" name="3"/>
+ <input class="led_color" type="hidden" name="[0]" readonly="true"/>
+ <input class="led_color" type="hidden" name="[1]" readonly="true"/>
+ <input class="led_color" type="hidden" name="[2]" readonly="true"/>
+ <input class="led_color" type="hidden" name="[3]" readonly="true"/>
</div>
<div>
- <div style="background: url('assets/images/wt_top.png'); background-size: cover; background-size: 100%; background-repeat: no-repeat; height: 260px;">
- <div class="d-flex justify-content-center" style="padding-top: 70px;">
- <input class="led_color" type="hidden" name="7"/>
- <input class="led_color" type="hidden" name="6"/>
- <input class="led_color" type="hidden" name="5"/>
- <input class="led_color" type="hidden" name="4"/>
+ <div class="row wt-icon">
+ <div class="col-md-2 align-self-center bottom-leds">
+ <input class="led_color" type="hidden" name="[14]" readonly="true"/>
+ <input class="led_color" type="hidden" name="[15]" readonly="true"/>
+ </div>
+ <div class="col-md-8">
+ <div class="d-flex justify-content-center top-leds">
+ <input class="led_color" type="hidden" name="[7]" readonly="true"/>
+ <input class="led_color" type="hidden" name="[6]" readonly="true"/>
+ <input class="led_color" type="hidden" name="[5]" readonly="true"/>
+ <input class="led_color" type="hidden" name="[4]" readonly="true"/>
+ </div>
+ </div>
+ <div class="col-md-2 align-self-center bottom-leds">
+ <input class="led_color" type="hidden" name="[13]" readonly="true"/>
+ <input class="led_color" type="hidden" name="[12]" readonly="true"/>
</div>
</div>
</div>
<div class="d-flex justify-content-center">
- <input class="led_color" type="hidden" name="8"/>
- <input class="led_color" type="hidden" name="9"/>
- <input class="led_color" type="hidden" name="10"/>
- <input class="led_color" type="hidden" name="11"/>
+ <input class="led_color" type="hidden" name="[8]" readonly="true"/>
+ <input class="led_color" type="hidden" name="[9]" readonly="true"/>
+ <input class="led_color" type="hidden" name="[10]" readonly="true"/>
+ <input class="led_color" type="hidden" name="[11]" readonly="true"/>
</div>
</div>
- <div class="col-md-1">
- <div class="float-left align-middle">
- <input class="led_color" type="hidden" name="13"/>
- <input class="led_color" type="hidden" name="12"/>
+ <div class="col-md-3 offset-md-1">
+ <div class="form-group row">
+ <label class="col-sm-2 col-form-label">Alle</label>
+ <div class="col-sm-10">
+ <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"/>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-sm-2 col-form-label">Front</label>
+ <div class="col-sm-10">
+ <input class="led_color" type="text" name="[0, 1, 2, 3]" class="form-control" readonly="true"/>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-sm-2 col-form-label">Aft</label>
+ <div class="col-sm-10">
+ <input class="led_color" type="text" name="[8, 9, 10, 11]" class="form-control" readonly="true"/>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-sm-2 col-form-label">Top</label>
+ <div class="col-sm-10">
+ <input class="led_color" type="text" name="[4, 5, 6, 7]" class="form-control" readonly="true"/>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-sm-2 col-form-label">Bottom</label>
+ <div class="col-sm-10">
+ <input class="led_color" type="text" name="[12, 13, 14, 15]" class="form-control" readonly="true"/>
+ </div>
</div>
</div>
</div>
</div>
+ <div id="drive" class="tab-pane" role="tabpanel">
+ <div class="cmd_vel_circle"></div>
+ </div>
</div>
</div>
<script src="assets/javascripts/jquery-3.3.1.min.js"></script>
<script src="assets/javascripts/nav2d.js"></script>
<script src="assets/javascripts/keyboardteleop.js"></script>
<script src="assets/javascripts/jquery.minicolors.js"></script>
+ <script src="assets/javascripts/vue.js"></script>
</body>
</html>