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

****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

AttachmentSize

Comment viewing options

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

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 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.

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

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 :-)

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?

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

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.

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

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*