Shop OBEX P1 Docs P2 Docs Learn Events
bicycle computer on the javelin stamp — Parallax Forums

bicycle computer on the javelin stamp

PlaneTeeRPlaneTeeR Posts: 100
edited 2006-04-18 17:28 in General Discussion
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

Comments

  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-04-13 09:12
    There is the CPU.pulseIn() method, but this does not return until it
    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
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-04-13 12:11
    If your sensor is like a small wheel that is pressed against your bike wheel,
    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
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-04-13 12:37
    Looks like I reversed the formula.

    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
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-04-13 12:55
    If you want to calculate distance, then you
    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
  • PlaneTeeRPlaneTeeR Posts: 100
    edited 2006-04-14 20:54
    Dear Peter,

    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
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-04-14 21:11
    Do you have a datasheet of your sensor?
    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
  • PlaneTeeRPlaneTeeR Posts: 100
    edited 2006-04-16 19:38
    Peter Verkaik said...

    There is the CPU.pulseIn() method, but this does not return until it
    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

    Dear Peter, I have tested the code that you've given here, and it works excellent. But here's the thing, I haven't got a clou how that program works. I know a little java but this I can't understand. Can you explain it to me?

    Thanks Johnny
    The Netherlands
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-04-16 20:04
    The idea is to count the number of positive and negative edges
    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
  • PlaneTeeRPlaneTeeR Posts: 100
    edited 2006-04-16 21:06
    Dear Peter,

    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
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-04-16 21:30
    You need to supply a value for timeout.

    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
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-04-16 22:13
    To measure the total pulse time you can use

    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
  • PlaneTeeRPlaneTeeR Posts: 100
    edited 2006-04-16 22:15
    Dear 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
    921 x 697 - 85K
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-04-16 22:33
    That really depends on the number of pulses per second that is outputted.
    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
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-04-18 05:52
    Here are documents regarding Hall Effect sensors
    http://www.melexis.com/prodmain.asp?Family=MLX90217
    regards peter

    Post Edited (Peter Verkaik) : 4/18/2006 5:56:04 AM GMT
  • PlaneTeeRPlaneTeeR Posts: 100
    edited 2006-04-18 14:15
    Dear Peter,

    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
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-04-18 14:34
    Try this:

    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
  • PlaneTeeRPlaneTeeR Posts: 100
    edited 2006-04-18 14:46
    First i started slow then i went crazy with the thing, then again slow and stopped.

    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
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-04-18 15:10
    It looks like the high period has a fixed length of·3,
    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
  • PlaneTeeRPlaneTeeR Posts: 100
    edited 2006-04-18 15:43
    I got this, what does this conclude?



    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
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-04-18 16:21
    Your sensor outputs a pulse with high period fixed length of 3, and a variable length
    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
  • PlaneTeeRPlaneTeeR Posts: 100
    edited 2006-04-18 17:05
    This programm give this as result (just before·the negative number·I moved the magnet fast·I stoped around de last high number)

    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
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2006-04-18 17:28
    The negative numbers are actually numbers greater than 32767
    (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
Sign In or Register to comment.