BS2 Decimal Math Help!
RGuyser
Posts: 90
Hello. I want to use my BS2 for positioning task. I must divide a decimal number representing a distance by a decimal number representing a machine resolution. The code will eventually produce one TTL pulse for each unit of travel(resolution)... I would prefer 3 or 4 decimal places. Also, being able to handle negative and positive numbers would be great!
Please help! I have looked at the FPU unit, but would very much prefer to avoid that if there is a code only solution. I look forward to any advice.
Robert
SO...(Roughly, i am no PBASIC Wiz, and dont have the editor on hand).
main:
DEBUGIN "Enter distance to travel (xx.xxxx), distance, CR
DEBUGIN "Enter Resolution(Duistance/Pulse in xx.xxxx), resolution, CR
distance / resolution = steps
[noparse][[/noparse]Insert code to round steps to nearest whole number] 'Something with the <<, >> command, i figure. no idea! Result is WholeSteps
steps - WholeSteps = tolerance 'this displays how much deviance from the absolute location we achieve based on resolution
DEBUG tolerance, CR 'Display tolerance
Goto Motion
motion:
[noparse][[/noparse]INSERT CODE FOR MOTION CONTROL] 'I will worry about this later. I am more confident here
goto main
end sub
Goto Main
end
Please help! I have looked at the FPU unit, but would very much prefer to avoid that if there is a code only solution. I look forward to any advice.
Robert
SO...(Roughly, i am no PBASIC Wiz, and dont have the editor on hand).
main:
DEBUGIN "Enter distance to travel (xx.xxxx), distance, CR
DEBUGIN "Enter Resolution(Duistance/Pulse in xx.xxxx), resolution, CR
distance / resolution = steps
[noparse][[/noparse]Insert code to round steps to nearest whole number] 'Something with the <<, >> command, i figure. no idea! Result is WholeSteps
steps - WholeSteps = tolerance 'this displays how much deviance from the absolute location we achieve based on resolution
DEBUG tolerance, CR 'Display tolerance
Goto Motion
motion:
[noparse][[/noparse]INSERT CODE FOR MOTION CONTROL] 'I will worry about this later. I am more confident here
goto main
end sub
Goto Main
end
Comments
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
1+1=10
So. The purpose of this is to move parts accurately for drilling holes on a drill press.. The actuators are screws driven by steppers.. if the screw takes 20 rotations to move 1 inch, and the steper takes 400 pulses to move one rotation that is:
1 / (20*400) = .000125 in/step resolution
Lets say I want to move 1.635 inches:
1.635 / .000125 = 13080 steps.
this was easy as 1.635 is divisible by .000125.
The hardware then outputs 13080 pulses on an IO line, stepping a stepper controller.
Please Help or Advise!
Given your setup, a maximum travel of 8.192 inches can be fit into a 16 bit number. I would keep the units in steps internally, and perform a translation from the input into steps.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
1+1=10
Post Edited (Paul Baker) : 6/1/2006 9:18:33 PM GMT
"It can be done, just adjust the values to incorporate the fractions. Say you want 3 decimal places, then the value of 1 would be represented by 1000, 4.506 is 4506 etc. Keep in mind that however many decimal places you include, you are taking away from the integer portion. A BS2 uses 16 bit (word) variables, which has a maximum value of 65535, so having 3 decimal places leaves a maximum integer value of 65. To get more you would have to use 32 bit math, heres a guide on doing that: http://www.emesystems.com/BS2math6.htm"
Ah, I see. So, if I wanted to use .000125 as a constant divisible, I would have to incorporate these 32 bit math 'routines' (or whatever they are). Complex, but I suppose worth it.
Another question arrises, how do i let the user input a decimal number? (ie 6.742) I think I remember seeing code somewhere that would do this? Ideally I will eventually have an LCD and a keypad matrix for this task... Ideally... In the mean time, I am just trying to figure out the core 'motion-engine'
Thanks for the quick response!
Anyone know of any example code i could look at that would answer some of these questions?
Thanks!
i am going to study this link you have provided though - it seems like a hot ticket!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
1+1=10
After a quick check I have found my resolution will be either .000125 or .0000625 (20tpi / 800 or 1600 steps/rev)
My main application is for a small X\Ytable with about 6-8" travel in each direction. However, I would like to keep it flexible if possible, if all it takes to allow greater travels is a routine that breaks a large number into 2 16-bit words, that is fine..
I looked over that 32-bit math article. It is obviousely going to take a bit of time to understand. I probably have to wait till I am at home.. Not in my cubicle!
Thanks again. When I get home, I can post some links to pictures of the linear slide, for reference...
"You could use double precision with the number of inches in one word and the decimal fraction of an inch in the second word. In adding and subtracting, you just have to check for "inch carry" or "inch borrow". This might make displaying and entering the information easier."
I am afraid I dont completely understand. This is probably because I am something of a 'newbie' with programming microcontrollers. The whole process of shifting info in and out of xx-bit words is not something I am conversational in. As i understand your suggestion:
1. Ask for distance to travel as a whole integer. 6.325" would be (6325)
2. Assume resolution of .000125 - This is stored in a "double precision word"? This double precision word is 2 16-bit locations?
3. Divide input/resolution
It turns out with this resolution of .000125, and a movement in xx.xxx places, there is no rounding.. The same would be true for .0000625.
- LOOKUP steps&%11111,[noparse][[/noparse]0,625,1250,1875,2500,3125,3750,4375,...],xxx
- DEBUG DEC inches,".",DEC3 steps>>5,DEC3 xxx
where the LOOKUP gives you the last 4 digits corresponding to the number of steps within 0.001 inch. I only included the first 8 step sizes. You should get the idea. It's similar with 16000 steps per inch.
- LOOKUP steps&%111,[noparse][[/noparse]0,125,250,375,500,625,750,875],fract
- DEBUG DEC2 inches,".",DEC3 steps>>3,DEC3 fract
At 1600 steps per rev or 32000 steps per inch, it looks like:
- LOOKUP steps&%1111,[noparse][[/noparse]0,0625,1250,1875,2500,3125,3750,4375,5000,5625,6250,6875,7500,8125,8750,9375],fract
- DEBUG DEC2 inches,".",DEC3 steps>>4,DEC4 fract
When you're subtracting the resolution, keep in mind that you have to borrow an inch when there are fewer than 16000 steps or 32000 steps depending on the step size.
I think I understand the general idea.. But I need to be at the editor to figure out what this lookup code does. It is not totally obvious to me.
I cannot tell how the device takes a xx.xxx number and subtracts .000125 from it over and over until 0 using the code you have provided.. I think I need to do about a dozen short learning example programs... Unfortunately I do not compeltely understand the lookup command
LOOKUP steps&%11111,[noparse][[/noparse]0,625,1250,1875,2500,3125,3750,4375,...],xxx
this is a mystery to me without loading the documentation.. Something I look forward to doing after my arduous 1.25 hour commute home!
I really wish I understood your response better. I feel dumb and useless; like I am wasting time. I was hoping by asking before I did to much experimentation, I would be able to think this over on the commute and form a plan to quickly bang this out... You and Paul's input has allready helped alot, actually.. I will first work on a simple program that asks the user for 2 decimal numbers and stores them, and retrieves them... Then move onto mathematical operations on these numbers, then try this crazy lookup stuff you recomend..
My 'style' of programming is to look at as much applicable source code as i can find on any given problem and then hack it all together... this is why i am such a crummy programmer!
thanks for the help!
For entering the data, at the 10's position, just add or subtract 10 to the byte. At the 1's position, just add or subtract 1 to the inches byte. At the 0.1 inch position, add or subtract 100*8 or 100*16 to the "steps" word. At the 0.01 position, add or subtract 10*8 or 10*16. At the 0.001 position, add or subtract 8 or 16. To the right of that position, add or subtract 1 to change the fraction of 1/1000 inch. Obviously, you have to check for a valid number. You can easily tease out the various parts of the "steps" word with simple division and modulus (//) operators and check for limits (0 to 9) before incrementing or decrementing the digit.
-TenthsPosition:
- call getKeyPress ' Get a value into key
- if key = left then OnesPosition ' Previous position
- if key = right then HundredsPosition ' Next position
- value = (steps / base) / 100 // 10 ' Get actual digit
- if key = up then TenthsUp ' Check for up or down
- if value = 0 then TenthsPosition ' Lower limit
- steps = steps - (base * 100) ' Decrement
- goto TenthsPosition
-TenthsUp:
- if value = 9 then TenthsPosition ' Upper limit
- steps = steps + (base * 100) ' Increment
- goto TenthsPosition
-FractPosition:
- call getKeyPress
- if key = left then ThousandthsPosition
- if key = right then FractPosition ' No next position
- value = steps // base
- if key = up then FractUp
- if value = 0 then FractPosition
- steps = steps - 1
- goto FractPosition
-FractUp:
- if value = base-1 then FractPosition ' Upper limit
- steps = steps + 1
- goto FractPosition
Note: I'm assuming that getKeyPress displays the value in inches,steps when it's first entered so the display is up to date.
-StepLoop:
- if inches = 0 and steps = 0 then allDone
- if steps > 0 then noBorrow
- steps = base * 1000
- inches = inches - 1
-noBorrow:
- steps = steps - 1
- call stepTheMotor
- goto StepLoop
I am trying to get this to work, ive got:
distInch VAR Byte
distDeci VAR Word
Main:
DEBUG CR,"Distance To Travel(x inches): ",CR
DEBUGIN DEC2 distInch
DEBUG "Distance .(xxx decimal): ",CR
DEBUGIN DEC4 distDeci
PAUSE 250
DEBUG CLS, "Distance to travel: ",DEC2 distInch,".", DEC3 distDeci
PAUSE 500
GOTO main
END
Which seems imperfect. Is there a better way to fill the initial variables?
After this initial gathering of data, using your method, I am supposed to: "Since the step sizes are powers of two in relation to 1/1000 of an inch (0/8, 1/8, 2/8, ... , 7/8) I decided to store this fraction of a 1/1000 inch in the lower 3 bits of the word. The upper 13 bits of the word stores the number of 1/1000 of an inch to the next inch."
I dont really follow. I am tempted to follow this method because it sounds like it will use much less code and therefor make integrating an LCD and keypad matrix alot easier in the long run than the 32-bit math stuff. However, I dont understand the exact mechanics of what you are recomending..
I am going to study your replys more and attempt to understand.. any further assitance is greatly appreciated.
if you are a curious fellow, you can see some of the sorts of stuff i am into www.robertguyser.com.... this explains why i am so programmatically challenged, but compelled to keep trying..
To do inches, it is total inches * 8000
So...
Get inches
Get thous
steps= (inches * 8000) + (thous * 8)
Hurrah... I think... Am I missing anything?
Now I will attempt to figure out how to use a keypad matrix and LCD... I suppose that will actually be harder than this was. Any hints on how to break the word-length barrier of the basic stamp so I can get travels above 7 inches?
' {$STAMP BS2}
' {$PBASIC 2.5}
inches VAR Byte
thous VAR Word
steps VAR Word
total VAR Word
x VAR Word
xxx VAR Word
main:
DEBUG CLS,"Distance to Travel 7 inches max! (x.xxx): "
DEBUGIN DEC1 inches ' Read in inches to travel
DEBUG "." ' after inches entered, display a decimal point
DEBUGIN DEC3 thous 'read in thous
DEBUG CR,"Total: ", DEC1 inches,".",DEC thous,CR 'display distance to go
DEBUG "Whole Inches: ", DEC1 inches, CR
DEBUG "Thousandths: " ,DEC3 thous, CR
x= inches * 8000
DEBUG "x steps:", DEC5 x,CR
xxx= thous * 8
DEBUG "xxx steps:", DEC5 xxx, CR
total = x+xxx
DEBUG "Total Steps to Move: ",DEC total, CR
PAUSE 5000
GOTO main
END
i var word
j var byte
...
for j=1 to inches
for i=1 to 8000
call stepOneStep
next
next
for i=1 to thous
for j=1 to 8
call stepOneStep
next
next