bicycle computer on the javelin stamp
PlaneTeeR
Posts: 100
Hello everyone,
I'm building the bicycle computer on the javelin stamp, and i'm trying to read the pulses. What is the best way to do this in java? Is there a sort of listener or threading?
The case is, the bicycle computer starts and must directly listen to pulses coming from the sensor and continue to do this.
Thanks Johnny
The Netherlands
Post Edited By Moderator (Chris Savage (Parallax)) : 4/13/2006 3:04:48 PM GMT
I'm building the bicycle computer on the javelin stamp, and i'm trying to read the pulses. What is the best way to do this in java? Is there a sort of listener or threading?
The case is, the bicycle computer starts and must directly listen to pulses coming from the sensor and continue to do this.
Thanks Johnny
The Netherlands
Post Edited By Moderator (Chris Savage (Parallax)) : 4/13/2006 3:04:48 PM GMT
Comments
has read the pulse or times out.
There is no listener as the javelin only has one thread.
You can do it manually in a loop
static final int pulsePin = CPU.pin0;
static boolean pulsePrev,pulseCurr;
static int posEdge=0, negEdge=0;
static Timer t = new Timer();
static int pulses=0;
static void main() {
· pulsePrev = pulseCurr = CPU.readPin(pulsePIn);
· t.mark();
· while (true) {
··· pulsePrev = pulseCurr;
··· pulseCurr = CPU.readPin(pulsePin);
··· if (pulseCurr && !pulsePrev) posEdge++; //count positive edges on pulsePin
··· if (!pulseCurr && pulsePrev) negEdge++; //count negative edges·on pulsePin
··· if (t.timeout(1000)) { //check counts every 1000 msec
····· t.mark();
····· pulses = (posEdge + negEdge + 1)>>>1; //calculate pulses
····· posEdge = negEdge = 0;
··· }
··· //other code here
· }
}
This only works for low frequency (long pulses) though.
For higher frequencies·(short pulses) I recommend to use an SX28 as coprocessor
or use a frequency to voltage converter chip which the Javelin
can read using its ADC virtual peripheral.
regards peter
you may be able to use pulseIn().
If D is your sensor wheel diameter in millimeters,
then speed in m/s = (N*2*pulseIn()*8.68/1000000) / ((D/1000)*pi)
where N is number of sensor pulses per full rotation of sensor wheel
So speed is constant * pulseIn()
This constant is likely to be a floating point so split it up
constant is integer + fraction
static int SKI = 100; //sensor constant integer part (example value)
static int SKF = 2345; //sensor constant fraction part for 65536 denominator
static void main() {
· int speed,pulse;
· while (true) {
····pulse = CPU.pulseIn(timeout,CPU.pin0,false);
··· speed = SKI*pulse + UnsignedIntMath.umulf(pulse,SKF);
··· System.out.println(speed); //display speed in m/s
··· //other code
··· CPU.delay(10500); //wait 1 second, only for demonstration and testing
· }
}
You find the UnsignedIntMath class here
http://groups.yahoo.com/group/JavelinCode/files/Javelin%20Stamp%20IDE/lib/stamp/math/
regards peter
Post Edited (Peter Verkaik) : 4/13/2006 12:25:41 PM GMT
speed in m/s = ((D/1000)*pi) / (N*2*pulseIn()*8.68/1000000)
so speed is constant / pulseIn or constant * freqIn
freqIn = 1/pulseIn·is < 1 and therefore a fraction
freqIn = UnsignedIntMath.ufrac(1,pulse);
So the example code becomes
static int SKI = 100; //sensor constant integer part (example value)
static void main() {
· int speed,pulse,freqIn;
· while (true) {
····pulse = CPU.pulseIn(timeout,CPU.pin0,false);
··· freqIn = UnsignedIntMath.ufrac(1,pulse);
··· speed = UnsignedIntMath.umulf(SKI,freqIn);
··· System.out.println(speed); //display speed in m/s
··· //other code
··· CPU.delay(10500); //wait 1 second, only for demonstration and testing
· }
}
regards peter
can integrate speed in time.
The Timer class has a method passedMS() that returns
the number of milliseconds past since last call to mark().
So distance += speed*t.passedMS()/1000; //accumulate distance in meters
static int SKI = 100; //sensor constant integer part (example value)
static Timer t = new Timer();
static int distance = 0;
static void main() {
· int speed=0,pulse,freqIn;
· while (true) {
··· distance += speed*t.passedMS()/1000;
··· t.mark();
····pulse = CPU.pulseIn(timeout,CPU.pin0,false);
··· freqIn = UnsignedIntMath.ufrac(1,pulse);
··· speed = UnsignedIntMath.umulf(SKI,freqIn);
··· System.out.println(speed); //display speed in m/s
··· //other code
··· CPU.delay(10500); //wait 1 second, only for demonstration and testing
· }
}
regards peter
Post Edited (Peter Verkaik) : 4/13/2006 1:26:18 PM GMT
Thanks for the fast and replies, you have shown some good codes and there are very usefull in our development!
The sensor that i use is a real bike computer sensor, i think its a hall sensor.
We use it to generate logical 0 to a pin. Is this code of yours enough for bicycle speeds? And is the code reusable (it never gets full)?
Again thanks for the replies, i will look in to the codes soon!
Thanks Johnny
The Netherlands
I assumed the number of pulses per second is proportional
to the speed of your bike. By using pulseIn() you get the time
for the high period of a pulse. I think you can safely assume
that your bike speed does not change for the adjacent
low period of the pulse, so the pulses have a 50% dutycycle.
(hence the 2*N in my formula)
If you assume the bike speed is constant within the
time to execute the while loop once, then you can
use pulseIn() because even if pulses are missed that
doesn't matter.
regards peter
Thanks Johnny
The Netherlands
for a duration of 1 second.
A positive edge has occured when the current input level is high
and the previous input level is low. --> if (pulseCurr && !pulsePrev) posEdge++;
A negative edge has occured when the current input level is low
and the previous input level is high. -->·if (!pulseCurr && pulsePrev) negEdge++;
A single pulse has one positive and one negative edge.
With rounding the number of pulses in 1 second --> pulses = (posEdge + negEdge + 1)>>>1;
I am glad this works, but I am sure you could also use pulseIn() as I explained in
the later examples. The problem with the count technique is that if edges are missed
the number of pulses decreases and this would falsely indicate a lower speed. This will most
likely happen if the other code in the mainloop occupies more time or when the
bike speed increases (the pulse length shortens then).
The use of pulseIn() implicitedly records the time for a single pulse, and assuming
adjacent pulses will have the same lenght (the bike speed will not change much in such
short time), pulses may even be missed for a correct speed calculation.
regards peter
Post Edited (Peter Verkaik) : 4/16/2006 8:17:17 PM GMT
I'm trying the pulseIn but it gives this fault:
pulse = CPU.pulseIn(timeout,CPU.pin0,false);· No Entity named timeout found in this enviroment!
What can i do?
Thanks Johnny
The netherlands
pulseIn
public static int pulseIn(int·timeout, int·portPin, boolean·pinState)Measure the length of a single pulse. Waits for the value of the selected pin to match the value selected by the state parameter and then times how long it takes for the pin to return to its original state. If the pin is an output then it will be changed to be an input and will remain as an input when complete.
A pulse of less than 8.68us in duration may be missed.
Parameters: timeout - the maximum amount of time to spend in the pulseIn method. The timeout covers the complete time of the process—both the wait for the start of the pulse and the time of the pulse. portPin - the I/O pin to measure the pulse on. pinState - whether to measure a high pulse (true) or a low pulse (false). Returns: the length of the pulse in 8.68us units. A value of 0 indicates that no start edge was detected. A value of -1 indicates that no stop edge was detected.
timeout is the number of 8.68 uSec ticks, so for timeout = 100, the timeout time is 868 uSec.
I think for a start, you best take a large timeout value. This also allows for longer pulses
(lower speed) to be measured.
pulse = CPU.pulseIn(28802,CPU.pin0,false);
allows for 0.25 sec --> pulseIn returns after max. 0.25 seconds
but normally pulse length is much smaller than 0.25 sec
(28802 * 8.68 uSec = ·250 millisec)
Note for the special return values:
0 indicates no start edge -> no pulse ->·speed = 0
-1 indicates no stop edge -> long pulse -> low speed
Since speed = constant/pulseIn()
you need to handle the case 0 anyway to prohobit division by zero error.
The constant value is totally determined by your sensor. In my example code
I assumed your sensor outputs a number of pulses that is proportional to your
bike speed. I also assumed these pulses have 50% dutycycle.
If the pulses have a fixed length high period and variable length low period (or vice versa)
(check datasheet or use a scope to find out) then the facter 2*N from
my example code must be changed to reflect·pulseTime equals·pulseIn()+constant
where pulseIn measures the variable length period.
regards peter
Post Edited (Peter Verkaik) : 4/16/2006 9:33:45 PM GMT
int lowperiod = CPU.pulseIn(28802,CPU.pin0,false); //measure negative period
int highperiod = CPU.pulseIn(28802,CPU.pin0,true); //measure positive period
int pulseperiod = lowperiod + highperiod; //total time pulse in 8.68 uSec ticks
The formula for freqIn becomes then
freqIn = 1/pulseperiod; //freqIn is a fraction
this works for variable length low and high periods even if not 50% dutycycle.
However, the assumption still is, that adjacent pulses have almost identical length,
because normally bike speed does not increase or decrease much in the short time
(0.25 sec or less) it takes to do and process a reading.
regards peter
I have no datasheet for the sensor because it is from an real bikecomputer, see the picture.
And on my school we have a scope so i have to wait a few days·for that!
What do you think is the best way in this case to use the pulsin or the loop method?
Thanks Johnny
The Netherlands
If you·you get a low number of pulses (< 10) for a low rotation speed of your
bikewheel then the count technique may work also at higher speeds.
The pulseIn method is probably the better way·because that also
works for higher speeds.
regards peter
http://www.melexis.com/prodmain.asp?Family=MLX90217
regards peter
Post Edited (Peter Verkaik) : 4/18/2006 5:56:04 AM GMT
I still·can't understand the·pulsin method that you described. I first want a normal program that only shows the pulses that it received, without calculating other stuff. Then in my second programming stage·I need to add the time, for the speed to be meassured it's needded to know the time between pulses. And last when i have all these numbers in my variabele i can start calculating the things like speed, distance·and so on which is the last step for this example.
How should·I program step 1 and 2?
Thanks Johnny
The Netherlands
static void main() {
· int lowperiod,highperiod;
· while (true) {
····lowperiod = CPU.pulseIn(28402,CPU.pin0,false); //measure low pulse width
····highperiod = CPU.pulseIn(28402,CPU.pin0,true); //measure high pulse width
··· System.out.print("low· period = "); //display low period ticks
··· System.out.println(lowperiod);
··· System.out.print("high period = "); //display high period ticks
··· System.out.println(highperiod);
··· System.out.print("total pulse = "); //display total pulse ticks
··· System.out.println(lowperiod+highperiod);
··· //other code
··· CPU.delay(10500); //wait 1 second, only for demonstration and testing
· }
}
That gives you an idea about the number of 8.68 microsecond ticks
for the low and high periods of the pulses. Longer periods indicate lower speeds.
regards peter
low· period = 0
high period = 0
total pulse = 0
low· period = 0
high period = 0
total pulse = 0
low· period = 0
high period = 0
total pulse = 0
low· period = 0
high period = 0
total pulse = 0
low· period = 2
high period = 3
total pulse = 5
low· period = 13385
high period = 3
total pulse = 13388
low· period = 11556
high period = 3
total pulse = 11559
low· period = 2
high period = 0
total pulse = 2
low· period = 1
high period = 0
total pulse = 1
low· period = 0
high period = 0
total pulse = 0
the low period increases with higher speeds.
Value 0 indicates no start edge (no pulse at speed=0)
change the line CPU.delay to
CPU.delay(1050); //wait 0.1 second
That gives you about 10 readings per second.
Just to get a better understanding how the periods
change with speed.
regards peter
low· period = 2
high period = 3
total pulse = 5
low· period = 2
high period = 2
total pulse = 4
low· period = 1
high period = 3
total pulse = 4
low· period = 2
high period = 3
total pulse = 5
low· period = 1
high period = 3
total pulse = 4
low· period = 2
high period = 3
total pulse = 5
low· period = 1
high period = 3
total pulse = 4
low· period = 2
high period = 3
total pulse = 5
low· period = 1
high period = 3
total pulse = 4
low· period = 1
high period = 3
total pulse = 4
low· period = 3859
high period = 3
total pulse = 3862
low· period = 1
high period = 3
total pulse = 4
low· period = 2
high period = 3
total pulse = 5
low· period = 1
high period = 3
total pulse = 4
low· period = 5357
high period = 3
total pulse = 5360
low· period = 2
high period = 3
total pulse = 5
low· period = 5361
high period = 3
total pulse = 5364
low· period = 1
high period = 4240
total pulse = 4241
low· period = 12519
high period = 4
total pulse = 12523
low· period = 2
high period = 3
total pulse = 5
low· period = 1
high period = 4
total pulse = 5
low· period = 1
high period = -1
total pulse = 0
low· period = 18019
high period = 3
total pulse = 18022
low· period = 1
high period = 3
total pulse = 4
low· period = 1
high period = 3
total pulse = 4
low· period = 1
high period = 0
total pulse = 1
low· period = 0
high period = 0
total pulse = 0
low period. I think you can assume that the low period length is proportional
to your bike wheel rotation speed, and thus proportional to bike speed.
The high period is only there to have a start edge (falling) and a stop edge
(rising). So there is no need to measure the high period.
Try this:
static void main() {
· int pulse;
· while (true) {
····pulse = CPU.pulseIn((short)0xFFFF,CPU.pin0,false); //measure low pulse width with max. timeout
··· System.out.print("pulse = "); //display low period ticks = proportional to speed
··· System.out.println(pulse);
··· //other code
··· CPU.delay(2100); //wait 0.2 second, 5 readings per second
· }
}
The values you get are (assumed) proportional to speed.
regards peter
pulse = 0
pulse = 0
pulse = 0
pulse = 0
pulse = 0
pulse = 0
pulse = 0
pulse = 2
pulse = 0
pulse = 1
pulse = 2
pulse = 1
pulse = 2
pulse = 1
pulse = 2
pulse = 1
pulse = 1
pulse = 2
pulse = 1
pulse = -28190
pulse = -28757
pulse = 1
pulse = 1
pulse = 1
pulse = 1
pulse = 1
pulse = 1
pulse = 1
pulse = 1
pulse = 1
pulse = 1
pulse = 1
pulse = 11471
pulse = 6858
pulse = 10341
pulse = 8295
pulse = 7780
pulse = 6756
pulse = 1
pulse = 2
pulse = 2
pulse = 2
pulse = 2
pulse = 1
pulse = 14359
pulse = 3
pulse = 26370
pulse = 2
pulse = 1
pulse = 1
pulse = 1
pulse = 1
pulse = 1
pulse = 0
pulse = 0
(add 65536 to the negative number to find the positive value)
The Format class allows you to print unsigned integer values,
the System.out prints only signed int values, hence the negative values.
Now you need to calibrate your sensor, that is, finding out how these
values relate to the bike speed. The easiest way to do this is to have
the sensor connected to both your bike computer (if that still works)
and the javelin. Then, at different speeds note the bike speed from
the bike computer and the low period count from the javelin.
If you then plot bike speed (y-axis) versus period count (x-axis), I expect the
measurements to be on a straight line. The tangent of the
angle this line makes with the x-axis is then your speed constant K.
Then speed = K * pulse
regards peter