Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
A Collaboration: Mechanical Odometer algorithm
#1
My son's coding of a locomotive powertrain modeling ap gave me the inspiration to try this one. A mechanical multi-wheel style counter. It's something of a father/son collaboration and was a fun head scratcher. I was pleased to see it would run in reverse too, except that it didn't like going below zero much. That would have to be trapped outside the SUB. Enjoy.

Code: (Select All)
'Odometer.bas  Richard & Erik Wessel
$COLOR:32
OPTION _EXPLICIT
SCREEN _NEWIMAGE(256, 216, 32)

DIM SHARED AS LONG slot, wheel, wheel10th
DIM AS DOUBLE miles

slot = _NEWIMAGE(56, 16, 32) '                                  numeral display window/limits
wheel = _NEWIMAGE(8, 176, 32) '                                 whole number counter wheels
wheel10th = _COPYIMAGE(wheel, 32) '                             1/10th counter wheel

makewheel Black, Bisque, wheel10th
makewheel Bisque, Black, wheel
miles = 0
DO
    CLS
    miles = miles + .002
    LINE (50, 50)-(206, 166), &HFF909090, BF
    Odometer miles
    _PUTIMAGE (100, 100), slot
    _LIMIT 30
    _DISPLAY
LOOP UNTIL _KEYDOWN(27)
END


SUB Odometer (m AS DOUBLE)
    DIM AS STRING mile_str
    DIM AS SINGLE mile_dec, roll
    DIM AS INTEGER dot_pos, overnine, dec_pos, dec_val, xpos, ypos, break
    mile_str = _TRIM$(STR$(m)) '
    IF INSTR(mile_str, "D") THEN '                              trap for early exponents here
        dot_pos = 1 '                                           give a non-zero value for computing mile_dec
    ELSE
        dot_pos = INSTR(mile_str, ".") '                        get decimal position if not an exponential
    END IF
    mile_dec = -(m - INT(m)) * (dot_pos <> 0) '                 get the decimal portion of the number
    roll = (mile_dec * 160) * (dot_pos <> 0) '                  roll factor of 1/10ths wheel mapped to number wheel
    overnine = ((mile_dec - .9) * -160) * (mile_dec > .9) '     get amount of roll past .9 if any
    overnine = overnine * (overnine < 17)
    _DEST slot '                                                draw to numeral display window
    _PUTIMAGE (_WIDTH(slot) - 8, INT(roll)), wheel10th '        set the 1/10ths wheel position & place in slot image
    FOR dec_pos = 1 TO INT(_WIDTH(slot) / 8) '                  iterate through whole number decimal places
        xpos = _WIDTH(slot) - 1 - 8 * (dec_pos + 1) '           get number wheel x position
        dec_val = VAL(MID$(mile_str, dot_pos - dec_pos, 1)) '   get decimal place value
        ypos = -16 * dec_val '                                  get whole number rotation position
        IF overnine AND NOT break THEN '                        if 1/10th wheel past .9 and no non-nine numbers previous
            ypos = ypos + overnine '                            add 9 to 0 rotation to decimal place
            IF dec_val <> 9 THEN break = -1 '                   if the number is not a 9 break from advancing the rest
        END IF
        _PUTIMAGE (xpos, ypos), wheel '                         set number wheel in slot window
    NEXT dec_pos
    _DEST 0 '                                                   done with slot image, return to screen
END SUB 'OdometerII


SUB makewheel (letter AS _UNSIGNED LONG, back AS _UNSIGNED LONG, dst AS LONG)
    DIM x%
    _DEST dst
    CLS , back
    COLOR letter
    _PRINTMODE _KEEPBACKGROUND
    FOR x% = 0 TO 9
        _PRINTSTRING (-8, x% * 16), STR$(x%)
    NEXT x%
    _PRINTSTRING (0, x% * 16), "0"
    _DEST 0
END SUB
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Reply
#2
Are we going to meet YoungMoses sometime soon?  Tell them to stop by and visit with us.  We'll be nice and hide Pete from him for at least a few days, so he won't be chased off immediately.  Big Grin
Reply
#3
(04-16-2025, 01:05 AM)SMcNeill Wrote: Are we going to meet YoungMoses sometime soon?  Tell them to stop by and visit with us.  We'll be nice and hide Pete from him for at least a few days, so he won't be chased off immediately.  Big Grin
I'll plant the suggestion. The family used to call me "the wizard" around these parts. I think it's safe to say he's assumed that mantle while I'm just an aged conjuror now. He recently conceived, designed and built a ladder logic control box to automate manual switching procedures at our grain elevator system. No microprocessors involved, just interlocking 3 form C relays to keep maintenance cheap and easy. Testing of the control promises to vastly streamline our harvest efficiency with limited manpower. We can't wait for the real world test in June.

He likes old world solutions to problems and doesn't care for computers in vehicles or equipment, but has a good head for coding all the same. When I'm describing algorithms to him, he grasps the concepts faster than I can relate them. You'll be hard pressed to find anyone with a better head for mechanics, hydraulics, electric circuits and probably a dozen things he has yet to put his mind to.

On topic, I made a few changes to make the counter a little more portable. This is serious gas guzzler...

Code: (Select All)
'Odometer.bas  Richard & Erik Wessel
$COLOR:32
OPTION _EXPLICIT
SCREEN _NEWIMAGE(256, 216, 32)

DIM SHARED AS LONG slot, slot2, wheel, wheel10th
DIM AS DOUBLE miles, gals

slot = _NEWIMAGE(56, 16, 32) '                                  numeral display window/limits
slot2 = _COPYIMAGE(slot, 32)
wheel = _NEWIMAGE(8, 176, 32) '                                 whole number counter wheels
wheel10th = _COPYIMAGE(wheel, 32) '                             1/10th counter wheel

makewheel Black, Bisque, wheel10th
makewheel Bisque, Black, wheel
DO
    CLS
    miles = miles + .002
    gals = gals + .006
    LINE (50, 50)-(206, 166), &HFF909090, BF
    Odometer miles, slot, 100, 100
    Odometer gals, slot2, 100, 132
    _LIMIT 30
    _DISPLAY
LOOP UNTIL _KEYDOWN(27)
END


SUB Odometer (m AS DOUBLE, ds AS LONG, ulx AS INTEGER, uly AS INTEGER)
    DIM AS STRING mile_str
    DIM AS SINGLE mile_dec
    DIM AS INTEGER dot_pos, overnine, dec_pos, dec_val, xpos, ypos, break, roll
    DIM AS LONG backimg
    mile_str = _TRIM$(STR$(m)) '
    IF INSTR(mile_str, "D") THEN '                              trap for early exponents here
        dot_pos = 1 '                                           give a non-zero value for computing mile_dec
    ELSE
        dot_pos = INSTR(mile_str, ".") '                        get decimal position if not an exponential
    END IF
    mile_dec = -(m - INT(m)) * (dot_pos <> 0) '                 get the decimal portion of the number
    roll = INT((mile_dec * 160) * (dot_pos <> 0)) '             roll factor of 1/10ths wheel mapped to number wheel
    overnine = ((mile_dec - .9) * -160) * (mile_dec > .9) '     get amount of roll past .9 if any
    overnine = overnine * (overnine < 17)
    backimg = _DEST
    _DEST ds '                                                  draw to numeral display window
    _PUTIMAGE (_WIDTH(ds) - 8, roll), wheel10th '             set the 1/10ths wheel position & place in slot image
    FOR dec_pos = 1 TO INT(_WIDTH(ds) / 8) '                  iterate through whole number decimal places
        xpos = _WIDTH(ds) - 1 - 8 * (dec_pos + 1) '           get number wheel x position
        dec_val = VAL(MID$(mile_str, dot_pos - dec_pos, 1)) '   get decimal place value
        ypos = -16 * dec_val '                                  get whole number rotation position
        IF overnine AND NOT break THEN '                        if 1/10th wheel past .9 and no non-nine numbers previous
            ypos = ypos + overnine '                            add 9 to 0 rotation to decimal place
            IF dec_val <> 9 THEN break = -1 '                   if the number is not a 9 break from advancing the rest
        END IF
        _PUTIMAGE (xpos, ypos), wheel '                         set number wheel in slot window
    NEXT dec_pos
    _DEST backimg '                                             done with slot image, return to screen
    _PUTIMAGE (ulx, uly), ds '                                  place counter to calling destination
END SUB 'Odometer


SUB makewheel (letter AS _UNSIGNED LONG, back AS _UNSIGNED LONG, dst AS LONG)
    DIM x%
    _DEST dst
    CLS , back
    COLOR letter
    _PRINTMODE _KEEPBACKGROUND
    FOR x% = 0 TO 9
        _PRINTSTRING (-8, x% * 16), STR$(x%)
    NEXT x%
    _PRINTSTRING (0, x% * 16), "0"
    _DEST 0
END SUB
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Reply
#4
(04-15-2025, 11:40 PM)OldMoses Wrote: My son's coding of a locomotive powertrain modeling ap gave me the inspiration to try this one. A mechanical multi-wheel style counter. It's something of a father/son collaboration and was a fun head scratcher. I was pleased to see it would run in reverse too, except that it didn't like going below zero much. That would have to be trapped outside the SUB. Enjoy.
I have made an adjustment to "fix" the rollover function so it handles rolling back below 0 or above 999999. These keys were added:
* Up - Odometer rolls forward (increment)
* End - Odometer stops
* Down - Odometer rolls backward (decrement)
* Insert - Reset odometer to 999999.5
* Delete - Reset odometer to 0.5
* Escape still quits

It is shown below and for easy downloading is attached to this message.

I wish I could take credit for the smooth rollover below 0 or above 999999, but that is thanks to OldMoses' great work!

Code: (Select All)
'Odometer.bas  Richard & Erik Wessel
'  Added up/down to change odometer direction and
'  to adjust for rollover - Paul Robinson 2025-04-16

'  Functions:
'  Key UP  - Odometer increases
'  Key END  - Odometer stops
'  Key DOWN - Odometer decreases
'  Insert - Reset odometer to 999999.5
'  Delete - Reset odometer to 0.5
'  Escape - quits


$Color:32
Option _Explicit

Screen _NewImage(256, 216, 32)
Dim Shared As Long slot, wheel, wheel10th
Dim As Double miles, advance
Const up = 18432, down = 20480, escape = 27
Const insert = 20992, delete = 21248
Const KeyEnd = 20224


slot = _NewImage(56, 16, 32) '                                  numeral display window/limits
wheel = _NewImage(8, 176, 32) '                                whole number counter wheels
wheel10th = _CopyImage(wheel, 32) '                            1/10th counter wheel

makewheel Black, Bisque, wheel10th
makewheel Bisque, Black, wheel

miles = 0
GoSub up

Do
    Cls
    miles = miles + advance
    If miles >= 1000000 Then miles = 0
    If miles < 0 Then miles = 1000000.0!
    Line (50, 50)-(206, 166), &HFF909090, BF
    Odometer miles
    _PutImage (100, 100), slot
    _Limit 30
    _Display

    If _KeyDown(up) Then GoSub up
    If _KeyDown(KeyEnd) Then advance = 0
    If _KeyDown(down) Then GoSub down
    If _KeyDown(insert) Then miles = 999999.5
    If _KeyDown(delete) Then miles = 0.5
Loop Until _KeyDown(escape)

End
up:
advance = .002
Return
down:
advance = -.002
Return
Sub Odometer (m As Double)
    Dim As String mile_str
    Dim As Single mile_dec, roll
    Dim As Integer dot_pos, overnine, dec_pos, dec_val, xpos, ypos, break
    mile_str = _Trim$(Str$(m)) '
    If InStr(mile_str, "D") Then '                              trap for early exponents here
        dot_pos = 1 '                                          give a non-zero value for computing mile_dec
    Else
        dot_pos = InStr(mile_str, ".") '                        get decimal position if not an exponential
    End If
    mile_dec = -(m - Int(m)) * (dot_pos <> 0) '                get the decimal portion of the number
    roll = (mile_dec * 160) * (dot_pos <> 0) '                  roll factor of 1/10ths wheel mapped to number wheel
    overnine = ((mile_dec - .9) * -160) * (mile_dec > .9) '    get amount of roll past .9 if any
    overnine = overnine * (overnine < 17)
    _Dest slot '                                                draw to numeral display window
    _PutImage (_Width(slot) - 8, Int(roll)), wheel10th '        set the 1/10ths wheel position & place in slot image
    For dec_pos = 1 To Int(_Width(slot) / 8) '                  iterate through whole number decimal places
        xpos = _Width(slot) - 1 - 8 * (dec_pos + 1) '          get number wheel x position
        dec_val = Val(Mid$(mile_str, dot_pos - dec_pos, 1)) '  get decimal place value
        ypos = -16 * dec_val '                                  get whole number rotation position
        If overnine And Not break Then '                        if 1/10th wheel past .9 and no non-nine numbers previous
            ypos = ypos + overnine '                            add 9 to 0 rotation to decimal place
            If dec_val <> 9 Then break = -1 '                  if the number is not a 9 break from advancing the rest
        End If
        _PutImage (xpos, ypos), wheel '                        set number wheel in slot window
    Next dec_pos
    _Dest 0 '                                                  done with slot image, return to screen
End Sub 'OdometerII


Sub makewheel (letter As _Unsigned Long, back As _Unsigned Long, dst As Long)
    Dim x%
    _Dest dst
    Cls , back
    Color letter
    _PrintMode _KeepBackground
    For x% = 0 To 9
        _PrintString (-8, x% * 16), Str$(x%)
    Next x%
    _PrintString (0, x% * 16), "0"
    _Dest 0
End Sub


Attached Files
.bas   odometer.bas (Size: 3.86 KB / Downloads: 11)
While 1
   Fix Bugs
   report all bugs fixed
   receive bug report
end while
Reply
#5
(04-16-2025, 11:39 AM)OldMoses Wrote: On topic, I made a few changes to make the counter a little more portable. This is serious gas guzzler...
And I have a revised one, only running the odometer backwards adds fuel!

Code: (Select All)
'Odometer2.bas  Richard & Erik Wessel

' Shows 2 odometers; one for mileage (kilometers), one for fuel consumption in gallons (liters)
'  Added up/down to change odometers direction and
'  to adjust for rollover - Paul Robinson 2025-04-16

'  Functions:
'' Functions:
' Key UP - Odometer increase, as does fuel consumption
' Key END - Odometer stops
' Key DOWN - Odometer decreases, as does fuel consumption
' Insert - Reset odometer to 999999.5, fuel to about 999996.1
' Delete - Reset odometer to 0.5, fuel to 1.5
' Escape - quits

'  If you don't want fuel consumption to decrease on odometer rollback,
'  change that at label "down:"


$Color:32
Option _Explicit
Screen _NewImage(256, 216, 32)

Dim Shared As Long slot, slot2, wheel, wheel10th
Dim As Double miles, gals, advance, fuelconsumption
Const up = 18432, down = 20480, escape = 27
Const insert = 20992, delete = 21248
Const KeyEnd = 20224


slot = _NewImage(56, 16, 32) '                                  numeral display window/limits
slot2 = _CopyImage(slot, 32)
wheel = _NewImage(8, 176, 32) '                                whole number counter wheels
wheel10th = _CopyImage(wheel, 32) '                            1/10th counter wheel

makewheel Black, Bisque, wheel10th
makewheel Bisque, Black, wheel

GoSub up

Do
    Cls
    miles = miles + advance
    If miles >= 1000000 Then miles = 0
    If miles < 0 Then miles = 1000000.0!

    gals = gals + fuelconsumption
    If gals >= 1000000 Then gals = 0
    If gals < 0 Then gals = 1000000.0!

    Line (50, 50)-(206, 166), &HFF909090, BF
    Odometer miles, slot, 100, 100
    Odometer gals, slot2, 100, 132
    _Limit 30
    _Display
    If _KeyDown(up) Then GoSub up
    If _KeyDown(KeyEnd) Then GoSub halt
    If _KeyDown(down) Then GoSub down
    If _KeyDown(insert) Then GoSub maxmiles
    If _KeyDown(delete) Then GoSub minmiles
Loop Until _KeyDown(escape)

End
up:
advance = .002
fuelconsumption = .006
Return
down:
advance = -.002
fuelconsumption = -.006
Return
halt:
advance = 0
fuelconsumption = 0
Return
maxmiles:
miles = 999999.5
gals = 999996.1
Return
minmiles:
miles = 0.5
gals = 1.5
Return



Sub Odometer (m As Double, ds As Long, ulx As Integer, uly As Integer)
    Dim As String mile_str
    Dim As Single mile_dec
    Dim As Integer dot_pos, overnine, dec_pos, dec_val, xpos, ypos, break, roll
    Dim As Long backimg
    mile_str = _Trim$(Str$(m)) '
    If InStr(mile_str, "D") Then '                              trap for early exponents here
        dot_pos = 1 '                                          give a non-zero value for computing mile_dec
    Else
        dot_pos = InStr(mile_str, ".") '                        get decimal position if not an exponential
    End If
    mile_dec = -(m - Int(m)) * (dot_pos <> 0) '                get the decimal portion of the number
    roll = Int((mile_dec * 160) * (dot_pos <> 0)) '            roll factor of 1/10ths wheel mapped to number wheel
    overnine = ((mile_dec - .9) * -160) * (mile_dec > .9) '    get amount of roll past .9 if any
    overnine = overnine * (overnine < 17)
    backimg = _Dest
    _Dest ds '                                                  draw to numeral display window
    _PutImage (_Width(ds) - 8, roll), wheel10th '            set the 1/10ths wheel position & place in slot image
    For dec_pos = 1 To Int(_Width(ds) / 8) '                  iterate through whole number decimal places
        xpos = _Width(ds) - 1 - 8 * (dec_pos + 1) '          get number wheel x position
        dec_val = Val(Mid$(mile_str, dot_pos - dec_pos, 1)) '  get decimal place value
        ypos = -16 * dec_val '                                  get whole number rotation position
        If overnine And Not break Then '                        if 1/10th wheel past .9 and no non-nine numbers previous
            ypos = ypos + overnine '                            add 9 to 0 rotation to decimal place
            If dec_val <> 9 Then break = -1 '                  if the number is not a 9 break from advancing the rest
        End If
        _PutImage (xpos, ypos), wheel '                        set number wheel in slot window
    Next dec_pos
    _Dest backimg '                                            done with slot image, return to screen
    _PutImage (ulx, uly), ds '                                  place counter to calling destination
End Sub 'Odometer


Sub makewheel (letter As _Unsigned Long, back As _Unsigned Long, dst As Long)
    Dim x%
    _Dest dst
    Cls , back
    Color letter
    _PrintMode _KeepBackground
    For x% = 0 To 9
        _PrintString (-8, x% * 16), Str$(x%)
    Next x%
    _PrintString (0, x% * 16), "0"
    _Dest 0
End Sub


Attached Files
.bas   odometer2.bas (Size: 4.7 KB / Downloads: 10)
While 1
   Fix Bugs
   report all bugs fixed
   receive bug report
end while
Reply
#6
Thanks for the controls. Those would have come in handy during development had I thought to put them in.
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Reply




Users browsing this thread: 1 Guest(s)