mirror of
https://github.com/Ekokumppanit/Bicyclesim.git
synced 2026-01-26 03:04:09 +00:00
Add speed sensor implementation for Arduino Leonardo. Adapt simulation code to use data from Arduino.
This commit is contained in:
@@ -16,9 +16,6 @@ a speed sensor.
|
||||
|
||||
## Speed sensor
|
||||
|
||||
Most basic speed sensor would be "Keyboard" that sends a keypress whenever the wheel has turned one revolution.
|
||||
~~This kind of sensor can be built from a old keyboard by soldering a reed switch to right conductors at keyboard circuit board. Some instructions here: http://www.instructables.com/id/Hacking-a-USB-Keyboard/.~~
|
||||
Doesn't work. The reed switch wont be closed long enough for the keyboard controller or computer to register wheel revolutions.
|
||||
Check arduino/arduino.ino for sample implementation for Arduino Leonardo.
|
||||
|
||||
It should be possible to build working device from Arduino Uno (http://mitchtech.net/arduino-usb-hid-keyboard/) or Arduino Due (http://www.i-programmer.info/news/91-hardware/4965-new-powerful-arduino-due-.html).
|
||||
Device should read the reed switch status every 1ms and send keypress maybe every 500ms (send 'a' if there was one wheel revolution since last keypress, send 'b' if two etc).
|
||||
It works as a keyboard and sends the number of wheel revolutions once per second.
|
||||
|
||||
67
arduino/arduino.ino
Normal file
67
arduino/arduino.ino
Normal file
@@ -0,0 +1,67 @@
|
||||
// Inspiration and parts of code from:
|
||||
// http://www.instructables.com/id/Arduino-Bike-Speedometer/
|
||||
|
||||
// Connect the reed between 5V and A0.
|
||||
// Add a 10kOhm resistor between ground and A0.
|
||||
|
||||
#define reed A0 // pin connected to read switch
|
||||
|
||||
// 80ms per wheel rev:
|
||||
// (28 inch * pi) / (80 millisecond) = 100.543531 km/h
|
||||
const int DEBOUNCE = 80; // 100 * 1/(1kHz) = 100ms
|
||||
|
||||
int val;
|
||||
int revs = 0;
|
||||
int counter = 0;
|
||||
|
||||
void setup() {
|
||||
pinMode(reed, INPUT);
|
||||
|
||||
cli();
|
||||
|
||||
// set timer1 interrupt at 1kHz
|
||||
TCCR1A = 0;// set entire TCCR1A register to 0
|
||||
TCCR1B = 0;// same for TCCR1B
|
||||
TCNT1 = 0;
|
||||
// set timer count for 1khz increments
|
||||
OCR1A = 1999;// = (1/1000) / ((1/(16*10^6))*8) - 1
|
||||
// turn on CTC mode
|
||||
TCCR1B |= (1 << WGM12);
|
||||
// Set CS11 bit for 8 prescaler
|
||||
TCCR1B |= (1 << CS11);
|
||||
// enable timer compare interrupt
|
||||
TIMSK1 |= (1 << OCIE1A);
|
||||
|
||||
sei();
|
||||
|
||||
Keyboard.begin();
|
||||
}
|
||||
|
||||
// 1kHz timer
|
||||
ISR(TIMER1_COMPA_vect) {
|
||||
val = digitalRead(reed);
|
||||
if (val) {
|
||||
if (counter == 0) {
|
||||
++revs;
|
||||
counter = DEBOUNCE;
|
||||
} else if (counter > 0) {
|
||||
--counter;
|
||||
}
|
||||
} else if (counter > 0) {
|
||||
--counter;
|
||||
}
|
||||
}
|
||||
|
||||
void output() {
|
||||
if (revs > 9) {
|
||||
Keyboard.write('a' + revs - 10);
|
||||
} else if (revs > 0) {
|
||||
Keyboard.write('0' + revs);
|
||||
}
|
||||
revs = 0;
|
||||
}
|
||||
|
||||
void loop(){
|
||||
output();
|
||||
delay(1000);
|
||||
}
|
||||
@@ -66,18 +66,18 @@
|
||||
<p>
|
||||
<a href="http://www.ekokumppanit.fi" target="new">Ekokumppanit Oy:n</a> työntekijä Juho Teperi on toteuttanut tämän prototyyppi web-sovelluksen
|
||||
<a href="http://www.expomark.fi/fi/messut/energia2012" target="new">Energia 2012</a> messuja varten.
|
||||
Ohjelmassa voit liikkua (polkea) ympäri maailmaa (tai ainakin valmiita reittejä).
|
||||
Ohjelmassa voit liikkua polkemalla ympäri maailmaa tai ainakin valmiita reittejä.
|
||||
</p>
|
||||
|
||||
<h1>Käyttö</h1>
|
||||
<p>
|
||||
Omalla koneellasi voit kokeilla toimintaa valitsemalla <em>Simulaatio</em>-välilehdeltä reitin ja hakkaamalla välilyöntiä.
|
||||
Parhaan kokemuksen saat kun liität tietokoneeseen polkupyörän telineen <small>(traineri tai rolleri)</small> ja nopeusanturin <small>(laite joka lähettää näppäinpainalluksen kun rengas on pyörähtänyt kierroksen)</small> avulla.
|
||||
Omalla koneellasi voit kokeilla toimintaa valitsemalla <em>Simulaatio</em>-välilehdeltä reitin ja hakkaamalla näppäimistöltä numeroita 1-9 ja kirjamia a-f.
|
||||
Parhaan kokemuksen saat kun liität tietokoneeseen polkupyörän telineen ja nopeusanturin avulla. Nopeusanturina toimii laite joka lähettää näppäinpainalluksen kun rengas on pyörähtänyt kierroksen.
|
||||
</p>
|
||||
|
||||
<h1>Toteutus</h1>
|
||||
<p>
|
||||
Ohjelma on toteutettu käyttäen <a href="http://meteor.com" target="new">Meteor</a> JavaSript sovelluskehystä <small>(käyttää palvelinpuolella Node.js)</small>.
|
||||
Ohjelma on toteutettu käyttäen <a href="http://meteor.com" target="new">Meteor</a> JavaSript sovelluskehystä.
|
||||
Kuvat tulevat Google Streetview palvelusta Googlen tarjoaman JavaScript rajapinnan kautta.
|
||||
</p>
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
<p>
|
||||
Voit joko käyttää valmista ohjelmaa osoitteessa <a href="http://bicyclesim.ekokumppanit.fi">bicyclesim.ekokumppanit.fi</a> tai
|
||||
hakea ohjelman lähdekoodin <a href="http://github.com/Ekokumppanit/Bicyclesim" target="new">Githubista</a>,
|
||||
voit myös tehdä vapaasti muutoksia koodiin ja lähettää parannuksesi viralliseen versioon jotta muutkin hyötyvät niistä.
|
||||
voit myös tehdä vapaasti muutoksia koodiin.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,38 +1,64 @@
|
||||
window.point = null;
|
||||
window.traveled = 0;
|
||||
|
||||
function move () {
|
||||
// var dist = localStorage['multiplier'] * c();
|
||||
var dist = localStorage['multiplier'] * 0.1 * Session.get('speed');
|
||||
var createRingBuffer = function (length){
|
||||
var pointer = 0, buffer = [], sum = 0;
|
||||
|
||||
return {
|
||||
push: function (item) {
|
||||
if (buffer[pointer] > 0) {
|
||||
sum -= buffer[pointer];
|
||||
if (sum <= 0) sum = 0;
|
||||
}
|
||||
buffer[pointer] = item;
|
||||
sum += item;
|
||||
pointer = (length + pointer + 1) % length;
|
||||
},
|
||||
sum: function () {
|
||||
return sum;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var revs = 0;
|
||||
$(document).bind('keydown', function (e) {
|
||||
if (e.keyCode > 48 /* 0 */ && e.keyCode <= 57 /* 9 */) {
|
||||
revs += e.keyCode - 48;
|
||||
} else if (e.keyCode >= 65 /* a */ && e.keyCode <= 70 /* f */) {
|
||||
revs += e.keyCode - 65 + 10;
|
||||
}
|
||||
|
||||
if (revs === 0) return;
|
||||
|
||||
var dist = revs * c();
|
||||
revs = 0;
|
||||
Session.set('distance', Session.get('distance') + dist);
|
||||
window.traveled += dist;
|
||||
window.traveled += localStorage['multiplier'] * dist;
|
||||
|
||||
if (window.traveled >= window.point.distance) {
|
||||
var next = Points.findOne({_id: window.point.next});
|
||||
|
||||
// Go to next point, if one exists
|
||||
if (next) {
|
||||
window.traveled -= next.distance;
|
||||
window.traveled -= localStorage['multiplier'] * next.distance;
|
||||
|
||||
maps.travel(next._id, {route: true});
|
||||
window.point = next;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var speed_buffer = createRingBuffer(5 * 2);
|
||||
|
||||
var prev = 0;
|
||||
function speedo() {
|
||||
speed_buffer.push(Session.get('distance') - prev);
|
||||
prev = Session.get('distance') || 0;
|
||||
|
||||
Session.set('speed', speed_buffer.sum() / 5.0);
|
||||
}
|
||||
|
||||
var line = '';
|
||||
$(document).on('keydown', function (e) {
|
||||
if (e.keyCode === 13) { // enter
|
||||
if (line.length >= 1 && line[0] == 'S') {
|
||||
var speed = Number(line.slice(1));
|
||||
Session.set('speed', speed);
|
||||
$('.speedSlider').slider('value', speed);
|
||||
}
|
||||
line = '';
|
||||
} else {
|
||||
line += String.fromCharCode(e.keyCode);
|
||||
}
|
||||
});
|
||||
setInterval(speedo, 500);
|
||||
|
||||
Template.sim.speed = function () {
|
||||
return Session.get('speed');
|
||||
@@ -53,7 +79,6 @@ Template.sim.helpers({
|
||||
|
||||
window.init_sim = function init_sim() {
|
||||
|
||||
var i;
|
||||
Meteor.autosubscribe(function () {
|
||||
if (Session.equals('page', 'sim')) {
|
||||
var route = Routes.findOne({_id: Session.get('route')});
|
||||
@@ -74,22 +99,7 @@ Meteor.autosubscribe(function () {
|
||||
maps.lines.route.add(p.latlng);
|
||||
p = Points.findOne({_id: p.next});
|
||||
}
|
||||
|
||||
i = setInterval(move, 100);
|
||||
}
|
||||
|
||||
$('.speedSlider').slider({
|
||||
orientation: 'vertical',
|
||||
range: 'min',
|
||||
min: 0,
|
||||
max: 22.2, // m/s
|
||||
value: 0,
|
||||
slide: function (event, ui) {
|
||||
Session.set('speed', ui.value);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
i = clearInterval(i);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user