Skip to content

Commit

Permalink
gas and dir commands interface switched to sliders (#55)
Browse files Browse the repository at this point in the history
* pressed keys are displayed more visibly

* replaced inputs by sliders for commands (steering and gas)

* invert dir button works well now

* cleaned up code
  • Loading branch information
Vincent Houlbrèque committed May 10, 2018
1 parent 38d7abe commit 242db5c
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 87 deletions.
4 changes: 4 additions & 0 deletions front/static/css/styles.css
@@ -1,3 +1,7 @@
#stream {
width: 100%;
}

.oi {
font-size: 50px;
}
166 changes: 137 additions & 29 deletions front/static/js/main.js
Expand Up @@ -11,25 +11,102 @@ function showAlertStatus(data) {
}


$(document).ready( function() {
$('#model-group').hide();
$('#status').hide();
$('#control-group').hide();
$('#speed-group').hide();
$('#speed-limit').hide();

var pathname = window.location.pathname;

// In the commands tab, mode is training and started is True by default
// in order to test the different `commands` values easily
if (pathname == "/commands") {
socket.emit("mode_update", "training");
socket.emit("starter", true);
alert_data = {"type": "warning", "msg": "Training mode, started !"}
showAlertStatus(alert_data);
} else {
socket.emit("mode_update", "resting");
socket.emit("starter", false); // Stop the car when changing page
function retrieveCarState(callback) {
$.get( "/car_state", function(data) {
callback(data);
});
}

retrieveCarState(function(result) {
COMMANDS = result['commands'];

console.log('COMMANDS : ');
console.log(COMMANDS);

$(document).ready( function() {
$('#model-group').hide();
$('#status').hide();
$('#control-group').hide();
$('#speed-group').hide();
$('#speed-limit').hide();

var pathname = window.location.pathname;

// In the commands tab, mode is training and started is True by default
// in order to test the different `commands` values easily
if (pathname == "/commands") {
socket.emit("mode_update", "training");
socket.emit("starter", true);
alert_data = {"type": "warning", "msg": "Training mode, started !"}
showAlertStatus(alert_data);
} else {
socket.emit("mode_update", "resting");
socket.emit("starter", false); // Stop the car when changing page
}

});

// Directions bar
var sliderDir = document.getElementById('sliderDir');

if (sliderDir) {

var left = COMMANDS['left'];
var straight = COMMANDS['straight'];
var right = COMMANDS['right'];

noUiSlider.create(sliderDir, {
start: [left, straight, right],
connect: true,
range: {
'min': 200,
'max': 500
},
step: 1,
tooltips: true
});

sliderDir.noUiSlider.on('update', function(values, handle, unencoded, isTap, positions) {
c = ['left', 'straight', 'right'];
for (i=0; i<values.length; i++) {
socket.emit("command_update", {'command': c[i], 'value': parseInt(values[i], 10)});
}
});
}

// Gas bar
var sliderGas = document.getElementById('sliderGas');

if (sliderGas) {
var stop = COMMANDS['stop'];
var neutral = COMMANDS['neutral'];
var drive = COMMANDS['drive'];
var drive_max = COMMANDS['drive_max'];

noUiSlider.create(sliderGas, {
start: [stop, neutral, drive, drive_max],
connect: true,
range: {
'min': 200,
'max': 430
},
step: 1,
tooltips: true
});

sliderGas.noUiSlider.on('update', function(values, handle, unencoded, isTap, positions) {
var stop = values[0];
var neutral = values[1];
var drive = values[2];
var drive_max = values[3];

commands = ['stop', 'neutral', 'drive', 'drive_max'];

for (i=0; i<values.length; i++) {
socket.emit("command_update", {'command': commands[i], 'value': parseInt(values[i], 10)});
}

});
}

});
Expand Down Expand Up @@ -120,6 +197,7 @@ $("[data-command-reversed]").click(function(event) {
if (is_reversed) {
value = -1
}

socket.emit("command_update", {'command': 'invert_dir', 'value': value});
});

Expand All @@ -137,19 +215,49 @@ kinput.onkeydown = kinput.onkeyup = kinput.onkeypress = handle;

function handle(e) {

var elem = $("#control");

// Gas control
if (e.key == "ArrowDown" && e.type == "keydown" && !e.repeat){elem.removeClass().addClass('oi oi-caret-bottom'); socket.emit("gas", -1);}
if (e.key == "ArrowUp" && e.type == "keydown" && !e.repeat){elem.removeClass().addClass('oi oi-caret-top'); socket.emit("gas", 1);}
if (e.key == "ArrowUp" && e.type == "keyup" && !e.repeat){elem.removeClass().addClass('oi oi-media-pause'); socket.emit("gas", 0);}
if (e.key == "ArrowDown" && e.type == "keyup" && !e.repeat){elem.removeClass().addClass('oi oi-media-pause'); socket.emit("gas", 0);}
if (e.key == "ArrowUp" && e.type == "keydown" && !e.repeat) {
var elem = $("#controlUp");
elem.css('color', 'red');
socket.emit("gas", 1);
}
if (e.key == "ArrowUp" && e.type == "keyup" && !e.repeat) {
var elem = $("#controlUp");
elem.css('color', 'black');
socket.emit("gas", 0);
}
if (e.key == "ArrowDown" && e.type == "keydown" && !e.repeat) {
var elem = $("#controlDown");
elem.css('color', 'red');
socket.emit("gas", -1);
}
if (e.key == "ArrowDown" && e.type == "keyup" && !e.repeat) {
var elem = $("#controlDown");
elem.css('color', 'black');
socket.emit("gas", 0);
}

// Direction control
if (e.key == "ArrowLeft" && e.type == "keydown" && !e.repeat){elem.removeClass().addClass('oi oi-caret-left'); socket.emit("dir", -1);}
if (e.key == "ArrowRight" && e.type == "keydown" && !e.repeat){elem.removeClass().addClass('oi oi-caret-right'); socket.emit("dir", 1);}
if (e.key == "ArrowLeft" && e.type == "keyup" && !e.repeat){elem.removeClass().addClass('oi oi-media-pause'); socket.emit("dir", 0);}
if (e.key == "ArrowRight" && e.type == "keyup" && !e.repeat){elem.removeClass().addClass('oi oi-media-pause'); socket.emit("dir", 0);}
if (e.key == "ArrowLeft" && e.type == "keydown" && !e.repeat) {
var elem = $("#controlLeft");
elem.css('color', 'red');
socket.emit("dir", -1);
}
if (e.key == "ArrowLeft" && e.type == "keyup" && !e.repeat) {
var elem = $("#controlLeft");
elem.css('color', 'black');
socket.emit("dir", 0);
}
if (e.key == "ArrowRight" && e.type == "keydown" && !e.repeat) {
var elem = $("#controlRight");
elem.css('color', 'red');
socket.emit("dir", 1);
}
if (e.key == "ArrowRight" && e.type == "keyup" && !e.repeat) {
var elem = $("#controlRight");
elem.css('color', 'black');
socket.emit("dir", 0);
}

}

Expand Down
3 changes: 3 additions & 0 deletions front/static/js/nouislider.min.js

Large diffs are not rendered by default.

52 changes: 7 additions & 45 deletions front/templates/commands.html
Expand Up @@ -7,13 +7,15 @@
<h5>Pins</h5>
<p>You use the <code>direction_pin</code> and <code>gas_pin</code> to set the pin number on the Pi Hat.</p>
</div>

<div class="col-lg-8 mb-3">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">Direction Pin</span>
</div>
<input type="text" class="form-control" value="{{commands.dir_pin}}">
</div>

<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">Gas Pin</span>
Expand All @@ -29,28 +31,11 @@ <h5>Steering</h5>
<p><code>left</code>, <code>straight</code> and <code>right</code> parameters are used to send the direction order. You need to tune those values so that the Raspi sends the right PWM commands to the RC Car.</p>
<p>The <code>invert_dir</code> parameters defines the same commands but for reverse.</p>
</div>

<div class="col-lg-8 mb-3">
<div id="slider-handles"></div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">Left</span>
</div>
<input type="text" class="form-control" data-command="left" value="{{commands.left}}">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">Straight</span>
</div>
<input type="text" class="form-control" data-command="straight" value="{{commands.straight}}">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">Right</span>
</div>
<input type="text" class="form-control" data-command="right" value="{{commands.right}}">
</div>
<div id="sliderDir"></div></br>
<div class="input-group mb-3">
<button type="submit" class="btn btn-outline-primary" data-command-reversed="invert_dir">Invert Direction</button>
<button type="submit" class="btn btn-outline-primary" data-command-reversed="invert_dir">Invert Direction</button>
</div>
</div>
</div>
Expand All @@ -61,32 +46,9 @@ <h5>Gas</h5>
<p><code>stop</code>, <code>neutral</code> and <code>drive</code> are used to accelerate the car. You need to tune these parameters.</p>
<p><code>drive_max</code> is the maximum amount of gas. Be careful, on some cars, huge values can lead to a very fast (and uncontrollable) car!</p>
</div>

<div class="col-lg-8 mb-3">
<div id="slider-handles"></div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">Stop</span>
</div>
<input type="text" class="form-control" data-command="stop" value="{{commands.stop}}">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">Neutral</span>
</div>
<input type="text" class="form-control" data-command="neutral" value="{{commands.neutral}}">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">Drive</span>
</div>
<input type="text" class="form-control" data-command="drive" value="{{commands.drive}}">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">Drive Max</span>
</div>
<input type="text" class="form-control" data-command="drive_max" value="{{commands.drive_max}}">
</div>
<div id="sliderGas"></div>
</div>
</div>
</div>
Expand Down
37 changes: 31 additions & 6 deletions front/templates/index.html
Expand Up @@ -15,19 +15,41 @@
</div>
</div>
</div>

<!-- Display the models list -->
<div class="form-group" id="model-group">
<label for="inputAddress">Model </label>
<label>Model </label>
<select class="form-control" id="model_select">
<option selected>Choose model...</option>
{% for model in models %}
<option value='{{model}}'>{{model}}</option>
{% endfor %}
</select>
</div>
<div class="form-group" id="control-group">

<!-- Display the pressed keys -->
<div id="control-group">
<label>Control </label>
<p><span id="control" class="oi oi-media-pause"></span></p>
<p>
<div class="text-center">
<span id="controlUp" class="oi oi-caret-top"></span><br/>
</div>
<div class="row">
<div class="text-right col-lg-5">
<span id="controlLeft" class="oi oi-caret-left"></span>
</div>
<div class="text-left col-lg-2"></div>
<div class="text-left col-lg-5">
<span id="controlRight" class="oi oi-caret-right"></span><br/>
</div>
</div>
<div class="text-center">
<span id="controlDown" class="oi oi-caret-bottom"></span>
</div>
</p>
</div>

<!-- Display the different speed modes -->
<div class="form-row" id="speed-group">
<div class="form-group col-md-12">
<label>Speed Mode</label><br/>
Expand All @@ -38,14 +60,19 @@
</div>
</div>
</div>

<!-- Display the max speed slider -->
<div class="form-group" id="speed-limit">
<label id="maxSpeed">Max speed limit: 50%</label><br/>
<input type="range" id="maxSpeedSlider" oninput="maxSpeedUdate();">
</div>

<!-- Display the starter button -->
<button id="starter" class="btn btn-success btn-lg btn-block" disabled>Start</button>
</form>
</div>

<!-- Stream/Picture -->
<div class="col-lg-6 text-center mb-3">

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="stream" viewBox="0 0 250 150">
Expand All @@ -58,9 +85,7 @@
<image id="stream_image" xlink:href="/picture" x="0" y="0" height="150px" width="250px"/>
<line id="dirline" x1="125" y1="110" x2="25" y2="110" stroke="#f00" stroke-width="5" marker-end="url(#arrow)" visibility="hidden"/>
</svg>

<!-- <svg class="chart"></svg> -->


<div class="btn-group mt-1" role="group" aria-label="Basic example">
<button id="camera" class="btn btn-info">Start camera</button>
<button id="take-picture" type="button" class="btn btn-light">📸</button>
Expand Down
2 changes: 2 additions & 0 deletions front/templates/layout.html
Expand Up @@ -8,6 +8,7 @@
<!-- Bootstrap core CSS -->
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/open-iconic-bootstrap.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/nouislider.min.css') }}" rel="stylesheet" >
<link href="{{ url_for('static', filename='css/styles.css') }}" rel="stylesheet" >
</head>

Expand All @@ -34,6 +35,7 @@ <h5 class="my-0 mr-md-auto font-weight-normal">Ironcar Dashboard 🏎️</h5>
<script src="{{ url_for('static', filename='js/socket.io.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/d3.v4.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/nouislider.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/main.js') }}"></script>

</body>
Expand Down
1 change: 0 additions & 1 deletion ironcar.py
Expand Up @@ -133,7 +133,6 @@ def gas(self, value):
print('GAS : ', value)
else:
if self.verbose:
#print('PWM module not loaded')
print('GAS : ', value)

def dir(self, value):
Expand Down

0 comments on commit 242db5c

Please sign in to comment.