How to code "almost equals" or "pretty close"?

playback_test_of_table_head_moves.bas (5609Bytes)
playback_test_of_table_head_moves.bas (5609Bytes)

****Full code is attached****

In the code, b19 is increased all over the place. This variable is used in the "ran" select case subroutines to get a "random" move.

 

I use a simple subroutine for some of Walter's head moves. The calculation is simple, it is "where you are now" compared to "where you want to go". The sub routine knows "where the head is now" and recieves the 3 bytes as to "where the head should finish". It then calculates all the steps to get from A to B. In each loop, a check is made to see if we have gotten to our end point yet. Here is where my question lies. So here is the code:

servocalc:
for b11= 1 to 255 step 1
if b7>b4 then let b4=b4+b10 max b7
endif
if b4>b7 then let b4=b4-b10 min b7
endif
if b8>b5 then let b5=b5+b10 max b8
endif
if b5>b8 then let b5=b5-b10 min b8
endif
if b9>b6 then let b6=b6+b10 max b9
endif
if b6>b9 then let b6=b6-b10 min b9
endif
if b4=b7 and b5=b8 and b6=b9 then
return
endif
gosub servomove
pause 20
inc b19
next b11
return



servomove:
I2CSLAVE $C2, i2cslow, i2cbyte 'this is the i2c for the servo driver
writei2c 1,(b4)
writei2c 2,(b5)
writei2c 3,(b6)
pause b15
inc b19
return

Now, B4 B5 and B6 is where the head is now, and B7 b8 and b9 are where we are going. B10 is how big of steps we should take to get there (this is speed). The line at issue here is the one in bold.

if b4=b7 and b5=b8 and b6=b9 then
return
endif

If I use a value other than 1 in b10, the steps won't always add up to be an end number exactly and the line above will not ever be true. I need to code in something like this:

if b4=b7 +or- 2 and b5=b8 +or- 2 and b6=b9 +or-2 then return

 

https://www.youtube.com/watch?v=DehTJzbmCzo

The min and max functions don’t solve this?

The min and max functions don’t solve this?

I saw you post this code earlier this week and I felt the urge to rewrite it. This does not solve you problem, but it might make it a bit more clear.

servocalc:
do until b4=b7 and b5=b8 and b6=b9 ’ walk some more, until where you are = where you want to be
   if b4<b7 then let b4=b4+b10 max b7 endif
   if b4>b7 then let b4=b4-b10 min b7 endif

   if b5<b8 then let b5=b5+b10 max b8 endif   ’ why would this b5 overshoot b8?
   if b5>b8 then let b5=b5-b10 min b8 endif

   if b6<b9 then let b6=b6+b10 max b9 endif
   if b6>b9 then let b6=b6-b10 min b9 endif
   gosub servomove
loop
return

Maybe if…

Perhaps b5 would get out of whack when it overshoot 255. The max function would not notice. I doubt you are using values dangerously close the edge of the byte though.

I debugged this hole thing

I put a sertxd into the main calc loop and watched it go by during the whole loop. If I had a step of say 3, it would keep adding 3 to say b5 and it would not pass the max of b8. However, it would not equal b8 unless for some reason there was b8 was exactly devisable by 3. Let’s say the max was 20 and the start number was 0… It would be 0,3,6,9,12,15,18 and it would stop there. It would not add 3 more to the 18 because it would exceed the max of 20. It WILL NOT simply add 2 to get upto and including the max number. Again, this is the issue – 18 does not equal the max number and thus the final statement will never be true.

 

I do like however your do until/ loop system --I think it is more “programmerish” than a for/next loop.

right

Looks like “max” stands in the way of the final addition… Almost as if it is saying "feel free to add another 3 unless that would take it beyond 20.

Apart from the proper solution, do you have an extra byte to spare for a workaround?

Something like (pseudo code!):
b29 = abs(b8 - b5)   ’ this gives the absolute difference - something picaxe basic probably cannot give anyway
if b29 > b10 doitagain

error does not reproduce 8-(

In my simulator (!) I cannot reproduce your situation. This code simulates just fine as a picaxe28x1:

b4 = 2   b7 = 9
b5 = 2   b8 = 9
b6 = 2   b9 = 9
b10 = 3

gosub servocalc
pause 2000
end  ’   ALL bytes b4-b9 come out this end as 9 after three loops through the servocalc

servocalc:
for b11= 1 to 255 step 1
if b7>b4 then let b4=b4+b10 max b7
endif
if b4>b7 then let b4=b4-b10 min b7
endif
if b8>b5 then let b5=b5+b10 max b8
endif
if b5>b8 then let b5=b5-b10 min b8
endif
if b9>b6 then let b6=b6+b10 max b9
endif
if b6>b9 then let b6=b6-b10 min b9
endif
if b4=b7 and b5=b8 and b6=b9 then
return
endif
gosub servomove
pause 20
inc b19
next b11
return

servomove:
’ let’s pretend stuff happens here
return

What hardware are you using?

"do until … loop" better written as "do … loop until"

This code will save you one empty jump through the hoop:

symbol counter = b0
symbol stepper = 3
symbol goal    = 9
counter = 2

do
  pause 800   ’ the pause makes the simulation slow enough for us, meat bags
  counter = counter + stepper max goal
loop until counter = goal
pause 5000

One way around Picaxe’s limited arithmetics

One way around Picaxe’s limited arithmetics could be something like this:
symbol LIMIT      = 20
symbol HYSTERESIS = 3 ’ +/- 3
pause 1000
b0 = 17             ’ Value to compare

’ Calculate "absolute difference"
b1 = b0 - LIMIT
if b1 > 127 then    ’ “abs-hack”
    b1 = 256 - b1
endif

’ Check if we were close enough to LIMIT
if b1 <= HYSTERESIS then
    ’ Do something like …
    sound 0, (120,50) ’ … beep
endif

The code above is a workaround for missing negative values and abs function. It of course cuts the usable value range by half (if b1 > 127). The idea is that if b1 = b0 - LIMIT results to negative value ( >127 means 8th bit is set which means negative value in 8-bit arithmetics) then we turn it to positive value. Getting the positive value is simply subtracting the result from 256 (i.e. how much did the original subtraction “underflow”).

The code above isn’t really tested so expect bugs. It seemed to run just fine in the simulator though :slight_smile:

 

hardware and nummio

nummio --I think your code is what I need but man it adds some math time to the calc loop. There has got to be a better and smaller solution here.

Rik-- I am running the same code, without a simulate but with a sertxd for debugging and mine was showing a stop before the max.

Tell you what, gimme an hour and I will post video and debugging numbers.

Some data for you

I updated the post, there is a video showing the problem. Here is some sertxd data showing some numbers during the problem…

(This is stepping by 7)


<B4>38 <B5> 175 <b6> 64 'current servo pos
<B7> 1 <B8> 175 <b9> 64 'where we want to go --b8 and b9 have gotten there, just waiting for rotate to catch up
<B4>31 <B5> 175 <b6> 64
<B7> 1 <B8> 175 <b9> 64
<B4>24 <B5> 175 <b6> 64
<B7> 1 <B8> 175 <b9> 64
<B4>17 <B5> 175 <b6> 64
<B7> 1 <B8> 175 <b9> 64
<B4>10 <B5> 175 <b6> 64
<B7> 1 <B8> 175 <b9> 64
<B4>3 <B5> 175 <b6> 64
<B7> 1 <B8> 175 <b9> 64
<B4>252 <B5> 175 <b6> 64 '<<<< the loop starts over here. we want b7 to be one but it skips past and goes to 252.
<B7> 1 <B8> 175 <b9> 64
<B4>245 <B5> 175 <b6> 64
<B7> 1 <B8> 175 <b9> 64
<B4>238 <B5> 175 <b6> 64
<B7> 1 <B8> 175 <b9> 64
<B4>231 <B5> 175 <b6> 64
<B7> 1 <B8> 175 <b9> 64
<B4>224 <B5> 175 <b6> 64
<B7> 1 <B8> 175 <b9> 64

You are right, rik

I just went through a lot of debugging data and found something weird… You are right, the code will goto and include the min/max number… Just not always! I saw a bunch of numbers where the last move did not equal the step used and the number was indeed “caught” by the min/max and became the min/max. Other times, it is missed. It seems that if the “going to” number is 1 it has issues. I am going to try another run-through converting 1 into a number bigger than the step used and see what happens.

Yup, that’s it…

I added this to the “look up move routine” and it has solved all problems. It was the 1 and I don’t know why.

lookupmove:
readtable b14,b7,b8,b9
if b7=1 then let b7=8
endif
if b8=1 then let b8=8
endif
if b9=1 then let b9=8
endif
return

it DOES get to 1

Only AFTER reaching one does it go “under”. This tells me that your loop needs reprogramming indeed. Your code makes one more “loop for the road”. Make it stop in time!

The do … loop until construction elsewhere on this page will set you free.

crosses fingers

more…

I have found I have the same problem at the other end. You need to have room it seems for the min/max to catch stuff, I guess…

I have added this and everything is fixed. I still don’t know why

lookupmove:
readtable b14,b7,b8,b9
if b7=1 then let b7=b10+1
endif
if b8=1 then let b8=b10+1
endif
if b9=1 then let b9=b10+1
endif
if b7>230 then let b7=254-b10
endif
if b8>230 then let b8=254-b10
endif
if b9>230 then let b9=254-b10
endif
return

workaround

That workaround will only work for step size 7 or less. Perhaps if you said
if b7=1 then let b7=b10
you would regain a flexible stepsize again.

BUT, what if b7 urns out to be 2, or 3? or 4 or 5 or 6 or 7? I propose (still a workkaound):
if b7 < b10 then b7 = b10
which is equivalent to
b7 = b7 min b10

ting? I don’t think so. See my other comments for a better loop that needs no work around (just crossed fingers).

no it DOES NOT

dang this is confusing ■■■■

I misread. It goes from 3 to 252 aka -4. I hope you keep your head cool. Cool head moves BTW.

room

The picaxe first calculates the number and then checks the MIN MAX rules so

b1 = b1 - b10 MIN b7

will wrap around when b1 - b10 < 0 because the result (<0) is a large number that will be compared with b7. 

e.g. b1=5 : b10=7 and b7 = 4

step 1) the picaxe calcs b1 - b10 = -2 => 253

step 2) compare result 253 with the number 4

step 3) concludes the outcome 253 > 4 and therefore doesn’t need to be corrected to 4.

 

To make your code takes this into account with any speed setting on both ends of the byte, it should look like this.

let b0 = 255-b10

let b7 = b7 MIN b10 MAX b0

simulator confirms - half of it

The mystery is almost put to bed. As am I.

This hard coded program demonstrates

b1 = 250                        ’ 250
b1 = b1 + 9 max 252      ’ 252 (as expected)

b1 = 6                        ’    6
b1 = b1 - 9 min 2        ’ 253 (wrap around)

Is it because internally the calculation is done in a word, but even words have a bottom value of zero?

word to ya calculator!

w1 = 65530                      ’ 65530
w1 = w1 + 9 max 65532      ’      3

w1 = 6                        ’        6
w1 = w1 - 9 min 2        ’ 65533

Best practise from now on

Do you min’ing and max’ing BEFORE your subtracting and adding.

b1 = 250                        ’ 250
b1 = b1 max 243 + 9      ’ 252

b1 = 6                        ’   6
b1 = b1 min 11 - 9       ’   2