Automating Rotary Table

Home Model Engine Machinist Forum

Help Support Home Model Engine Machinist Forum:

This site may earn a commission from merchant affiliate links, including eBay, Amazon, and others.
When indexing with fractional increments none of the steps are an absolute value until they have been rounded. However, where each step represents 1.40625 seconds then the maximum linear error on the circumference of a 6" diameter circle would be .0000204531". That is derived from ((6 * π) / 921600). The servo motor steps per rotary table revolution is (2048 * 5 * 90) = 921600. The notion that leaving the error unmanaged improves the degree of precision is incomprehensible.

BTW, You have been misinformed on cmath. MS VS 2019 is the first version to include round and that is what I'm coding in. None of my code has cmath included yet it complied without errors. To make sure that cmath wasn't being called from another library I renamed cmath to cmathX and once again my code compiled without error.
 
It won't compile for me in Codeblocks without including cmath. Just throws an exception for an undefined function.
 
Microsoft is infamous for going "off reservation" with the way they implement numerous things, including languages. There is a standard that everyone else adheres to, and then there is Microsoft.

Which is to say, it is entirely possible that MS has put the round function in another library than called for in the C++ standard. But be assured it is in some library somewhere, because any and all functions are by definition part of the libraries, not part of the language itself.

Again, even without Microsoft's help, this distinction has gotten increasingly fuzzy, as C and C++ have added "standard libraries" to their definitions, as suggested above ... so in that sense one could argue that the libraries are in fact part of the language. From a compiler perspective, however, the distinction remains quite clear. The compiler knows exactly what + or - or struct or for or while or so on mean; it doesn't have to look anywhere else to turn that into machine code. But the compiler has no idea how perform round() or printf() or max() or so on. It knows only that they are functions, so it looks for them in the included libraries and hands off the task.
 
Microsoft is infamous for going "off reservation" with the way they implement numerous things, including languages. There is a standard that everyone else adheres to, and then there is Microsoft.

Which is to say, it is entirely possible that MS has put the round function in another library than called for in the C++ standard. But be assured it is in some library somewhere, because any and all functions are by definition part of the libraries, not part of the language itself.

Again, even without Microsoft's help, this distinction has gotten increasingly fuzzy, as C and C++ have added "standard libraries" to their definitions, as suggested above ... so in that sense one could argue that the libraries are in fact part of the language. From a compiler perspective, however, the distinction remains quite clear. The compiler knows exactly what + or - or struct or for or while or so on mean; it doesn't have to look anywhere else to turn that into machine code. But the compiler has no idea how perform round() or printf() or max() or so on. It knows only that they are functions, so it looks for them in the included libraries and hands off the task.

There's no disputing that the round function resides in cmath. However, when I can rename cmath to cmathX and successfully compile code that calls for the round function then that tells me that cmath is not the sole source for the round function. By renaming the library I eliminated the possibility of it being included by another library. That stated, if a function is not within the scope of a library then the library will not seek out other libraries. Else there would be no need to include more than 1 library.

The accuracy of my code should play very well with a rotary table that is certified to be accurate within 40 seconds. :( That seems to be the better end of the spectrum in machining rotary table accuracy.
 
By the way, which file did you rename - the cmath.h file? If so, that doesn't actually prevent the possibility that another library is calling the cmath library - if the other library has already been compiled, it will not need to refer to cmath.h. Nonetheless, it does indicate that the round function is defined somewhere else in MS's header files.
 
Last edited:
awake,

There is no cmath.h in VS 2019. As I explained if the function is not within the scope of a library then the library will not search other libraries for the function. If a function in a library calls for a function in another library then that library will be included in the library that is calling the function. Should the required library be cmath then the compiler will throw an error if the library is not available. I went a step beyond renaming the library and removed it from the folder. I was going to add round to math.h in VS 2010 Express but it made more sense to download the free VS 2019.

Assuming that you are using VS 2019 then locate the library file yvals_core.h and search for // P0092R1 <chrono> floor(), ceil(), round(), abs()
Once that you have found that string then scroll up to the top of that column and you will find // implemented unconditionally:
That library is used by the Compiler.

If you would like I will send you a copy of my app, My File Mole and it will read the files for you and log each occurrence of the search string in a list box. When you want to see the search in the file context then you simply click on the list box and it will load the file and highlight the search string. It's amazing what can be Learned at the Library. If you have a VB6 compiler available then I can send you the code.
 
Well, being pedantic again ... except in the case of a template library, the .h file is not the library; it is merely the header for the library. The actual library will consist either of statically linked object files, or of one or more .dll files.

Thank you for the offer, but for many years my OS of choice has been Linux, and grep already does that job quite well. Plus, having developed software since 1981, including quite a lot of embedded systems programming, I have a reasonably thorough understanding of the files on my system. :)

What I'm not personally familiar with is the various MS VS versions; my compiler of choice has been gcc and its stablemates. With that in mind, I'll bow out of this thread.
 
Its totally unreasonable to expect a small embedded CPU like the Atmel chips used by the Arduino to support the same features of the MS compiler which is written for CPU's with exponentially more processing power. Also you are failing to understand that floating point arithmetic is very expensive in terms of CPU processing.

Smart programmers avoid using floating point maths on the arduino. In fact the early incarnations of the Arduino library, it was something that needed an additional library to support. From memory, the floating point library consumed 4K of RAM which is huge in terms of the limited resources the Arduin Uno has at its disposal. This is why I say it is smart to work in seconds of a degree becasue that becomes the smallest divisions and then you can use integer maths and avoid the overhead of floating point. The other issue is that floats can cause errors because of the conversion of hexadecimal numbers (base 16) back to decimal (base 10) numbers. That is why some environments designed to support business applications introduce a new decimal data type which is a BCD (Binary coded decimal) that counts in base 10 maths. eg. This is a valid data type in SQL ( database which often stores business numbers). This error is less of an issue now when we have the processing power to deal with 64 bit numbers.

Back in the 70's when I first played with programming we quickly became acutely aware of the risks of using floating point and we would avoid it if at all possible. Back then, it was a big step to move from 8 bit to 16 bit processing. So, we used to have to do our own rounding. This is pretty easy to do. Lets assume a variable pi = 3.1417 and you want to round it to 3 decimals. So multiply it by 1000 ( pi * 1000 = 3141.7) then add 0,5 to it (3141.7 + 0.5 = 3142.2) so then take the int of that (3142). So now by divide by 1000, you end up with pi = 3.142. But the problem is that the use of hexadecimal maths might add errors back into this result so we would use string manipulation to ensure the number was formatted correctly when it was displayed. So this algorithim will correctly round up numbers where the decimal fraction is >= 0.5

So now you know how to write your own round function.
 
Rod, the problem the OP has is that his setup does not permit him to work in whole numbers of seconds. One step on the stepper motor does not translate into a whole number of seconds, so one way or another he is going to have to deal with fractions.

I will confess I have not looked through the code in any detail, but in general the "cost" of floating point is not so high that you can't or shouldn't use it in the interface part of the code, e.g., to calculate the resulting number of steps to move. Definitely shouldn't use FP inside a tight loop, of course, or worse yet in an interrupt.

It is possible, of course, to do some calculations using integer multiplication and division (the latter still not "cheap" on the 8-bit AVR, but still cheaper than FP), essentially working in fractions rather than in decimal. You divide the denominator into the numerator to get the steps, but keep track of the remainder in order to round as needed (and to avoid build up of error).

One minor point - I think you meant EEPROM rather than RAM when you were talking about the memory requirements for FP libraries. The Uno only has 2K of RAM, so if FP required 4K of RAM, it would definitely not work. :)

Oh, wait - I said above I was bowing out of this thread. Rats - hard for me not to jump into a conversation about embedded systems programming! Especially since, some 35 years ago, I had occasion to write a floating point library for an 8-bit system in assembler ...

Okay, this time I really am bowing out. Really. For sure ...
 
Its totally unreasonable to expect a small embedded CPU like the Atmel chips used by the Arduino to support the same features of the MS compiler which is written for CPU's with exponentially more processing power. Also you are failing to understand that floating point arithmetic is very expensive in terms of CPU processing.

Smart programmers avoid using floating point maths on the arduino. In fact the early incarnations of the Arduino library, it was something that needed an additional library to support. From memory, the floating point library consumed 4K of RAM which is huge in terms of the limited resources the Arduin Uno has at its disposal. This is why I say it is smart to work in seconds of a degree becasue that becomes the smallest divisions and then you can use integer maths and avoid the overhead of floating point. The other issue is that floats can cause errors because of the conversion of hexadecimal numbers (base 16) back to decimal (base 10) numbers. That is why some environments designed to support business applications introduce a new decimal data type which is a BCD (Binary coded decimal) that counts in base 10 maths. eg. This is a valid data type in SQL ( database which often stores business numbers). This error is less of an issue now when we have the processing power to deal with 64 bit numbers.

Back in the 70's when I first played with programming we quickly became acutely aware of the risks of using floating point and we would avoid it if at all possible. Back then, it was a big step to move from 8 bit to 16 bit processing. So, we used to have to do our own rounding. This is pretty easy to do. Lets assume a variable pi = 3.1417 and you want to round it to 3 decimals. So multiply it by 1000 ( pi * 1000 = 3141.7) then add 0,5 to it (3141.7 + 0.5 = 3142.2) so then take the int of that (3142). So now by divide by 1000, you end up with pi = 3.142. But the problem is that the use of hexadecimal maths might add errors back into this result so we would use string manipulation to ensure the number was formatted correctly when it was displayed. So this algorithim will correctly round up numbers where the decimal fraction is >= 0.5

So now you know how to write your own round function.
 
(IF) floating point numbers present a problem then all that I have to do is ditch the native Geometric unit of measure, seconds and substitute the servo motor ppr at the final drive which is 921600 ((2048 * 5) * 90). Divide the circumference of a 6" diameter circle by 921600 and that equals .00002045307717180855" linear error per user unit. At some point the processor is going to have to perform division or I guess that I could calculate the number of steps for the index and enter whole numbers. If there is a flaw in my logic then it will be the degree of precision returned from String.toFloat(). In Visual Basic 6.0 the degree of precision on type conversions is 4 places. In reality that amount of error far exceeds the rotary table's degree of precision. If the Arduino doesn't meet my expectations then I can always revert back to plan A which was to use a Galil Motion Control DMC-1830 DSP motion control board and base the rotary table control in the PC that hosts the motion control board for my CNC milling machine. I chose the Arduino approach because I did not want to make the rotary table integral to the machine. This project is too simple for your superior intelligence.
 
The result from the calculation is returned to the display before my finger clears the key. That's fast enough for me.
 
Last edited:
This project is too simple for your superior intelligence.

Ron, was this comment directed at my posts? I probably went into more depth than I should have, but I thought my last post was supporting you ... ??

The result from the calculation is returned to the display before my finger clears the key. That's fast enough for me.

Yep. That's the point, always - there are always ways to tweak the code just a bit more to wring just a bit more speed out of it, but if the code is fast enough, why bother?

For this project, ignorance is bliss and you don't need the experts. Just remember that, while it may be fast enough this time, you may attempt another project where the code can't keep up, and you find yourself wondering why your code is not working consistently (or at all). At that point, give us a call ...
 
The three of you continuously cited problems that did not exist. For a reason that I will never understand Cogsy had a problem with me using native units of Geometrical measurement. Assigning an arbitrary number of units to the table per revolution does not and cannot change the givens. I could have assigned the motor ppr at the final drive to the table per revolution and the resolution would have been the same. Sure in a perfect world the motor ppr at the final drive would have been equal to the seconds in 360 degrees but that is not what I have to work with. C++ is new to me but programming is not new to me. I have written several full feature CNC machine tool control operating systems in Visual Basic 6.0 for Galil Motion Control DMC1840 motion control boards. Half way through the first program I realized hat I chose the wrong language but I had too much time invested to start over and I never turned back. When and if my knowledge stands between me and success then I'm still quite capable of learning. The critique of my code was not solicited nor was I asking for help.

BTW, What part of the IEEE 754 standard for 32 bit floating point arithmetic is not implemented on an AVR Arduino?

Ron
 
Ron, that makes sense; I can see how that was frustrating, and I apologize.

I can't speak for the others, but my excuse is that I've written a good many embedded systems programs that required squeezing every last drop out of the processor, often to the point of counting cycles in the machine code to be sure an interrupt will be able to complete in time. It is easy to forget that sometimes, maybe lots of times, you just don't need to work that hard.

BTW, What part of the IEEE 754 standard for 32 bit floating point arithmetic is not implemented on an AVR Arduino?

Umm ... some, none, or all, depending on what exactly you are asking. The AVR microprocessor has no built-in floating point hardware, so any floating point operations have to be implemented by software. There's enough EEPROM to implement any or all of IEEE 754, if one chooses to do so -- or more likely for most of us, if the compiler one uses does so. If you are compiling using MS Visual Studio, the question is whether the Microsoft compiler fully implements IEEE 754 (likely). The Arduino IDE uses the gnu compiler, which in general fully implements IEEE 754 ... but which also has the option to relax some requirements: https://gcc.gnu.org/wiki/FloatingPointMath. Off hand, I don't know how, but I suppose it is possible to tell the IDE to set any of those options when it passes the code to the compiler ... but again, do you really need to work that hard? If it ain't broke ...
 
Ron, that makes sense; I can see how that was frustrating, and I apologize.

I can't speak for the others, but my excuse is that I've written a good many embedded systems programs that required squeezing every last drop out of the processor, often to the point of counting cycles in the machine code to be sure an interrupt will be able to complete in time. It is easy to forget that sometimes, maybe lots of times, you just don't need to work that hard.



Umm ... some, none, or all, depending on what exactly you are asking. The AVR microprocessor has no built-in floating point hardware, so any floating point operations have to be implemented by software. There's enough EEPROM to implement any or all of IEEE 754, if one chooses to do so -- or more likely for most of us, if the compiler one uses does so. If you are compiling using MS Visual Studio, the question is whether the Microsoft compiler fully implements IEEE 754 (likely). The Arduino IDE uses the gnu compiler, which in general fully implements IEEE 754 ... but which also has the option to relax some requirements: https://gcc.gnu.org/wiki/FloatingPointMath. Off hand, I don't know how, but I suppose it is possible to tell the IDE to set any of those options when it passes the code to the compiler ... but again, do you really need to work that hard? If it ain't broke ...

The answer to the closing question is NONE. The Arduino UNO rev3's only limitation at this time is that while it will accept double precision variables the level of precision remains single precision. I used to chuckle every time that I saw something about the Arduino and now here I am playing with one of them.

Ron
 
Ron, that makes sense; I can see how that was frustrating, and I apologize.

I can't speak for the others, but my excuse is that I've written a good many embedded systems programs that required squeezing every last drop out of the processor, often to the point of counting cycles in the machine code to be sure an interrupt will be able to complete in time. It is easy to forget that sometimes, maybe lots of times, you just don't need to work that hard.



Umm ... some, none, or all, depending on what exactly you are asking. The AVR microprocessor has no built-in floating point hardware, so any floating point operations have to be implemented by software. There's enough EEPROM to implement any or all of IEEE 754, if one chooses to do so -- or more likely for most of us, if the compiler one uses does so. If you are compiling using MS Visual Studio, the question is whether the Microsoft compiler fully implements IEEE 754 (likely). The Arduino IDE uses the gnu compiler, which in general fully implements IEEE 754 ... but which also has the option to relax some requirements: https://gcc.gnu.org/wiki/FloatingPointMath. Off hand, I don't know how, but I suppose it is possible to tell the IDE to set any of those options when it passes the code to the compiler ... but again, do you really need to work that hard? If it ain't broke ...

awake,

As they say, "The Proof is In the Pudding". That is 360º / 34 divisions. That is exactly what my debug loop in MS VS 2019 ended up with..... but it wouldn't do that a couple of hours ago. I declared the function getSteps() as long because steps ends up as a long value. However by using long I cast the floats to long and shut of my accumulate error handling routine along with inducing error. That result is derived by feeding the steps output back into the equation in reverse so it is the true position. I would not have found that error had I not 'read the display library'. It was in the library where I learned how to setprecision() without the standard namespace. Default is 2 places after the decimal point.

81849891_1100981053584382_2501561825624064000_o.jpg
 
Progress is slow due to work load. The shaft on the Vertex HV6 will not carry a sprocket so I made a tool steel sleeve to put over the rotary table spigot (for lack of a better word). A heavy duty 20mm wide needle bearing in the sprocket will run on the sleeve. The outer sprocket flange will be made from steel and it will drive the rotary table shaft. That arrangement will also shield the rotary table shaft from the belt tension. My code is attached. If you don't have an Arduino to run the sketch then do not comment on my logic. If you have an Arduino and you find an error that I have overlooked then I want to know about it so that I can correct it.

The 'D' key is dynamic in that it serves dual purposes within a screen. Jogging is performed in the Jogging screen. Select the increment and jogging begins. While jogging is active the 'D' key serves as an E-Stop. when jogging ceases then the 'D' resumes the role of the Exit button. The '#' key toggles CW/CCW. The '0' key returns the table to Home. It will eventually Home the rotary table. When time permits I will update the positioning screen so that it is like the jogging screen. Keypad stutter is common so while entering divisions or degrees the 'D' key becomes the Backspace key. Once that you have completely cleared the input then the 'D' key resumes the role of the Exit key.

If there is interest in how to create the involute curve for the HTD sprocket tooth profile then I will present a tutorial.


84565985_1123413654674455_8471839050242719744_o.jpg
84946938_1123413818007772_8545981941097168896_o.jpg
86333160_1123413948007759_8773339316265943040_o.jpg
86291549_1125325357816618_6090976568824299520_o.jpg
 

Attachments

  • INDEXER_.zip
    2.9 KB · Views: 333
Last edited:
The three of you continuously cited problems that did not exist. For a reason that I will never understand Cogsy had a problem with me using native units of Geometrical measurement.

Ron, just caught up on this thread and noticed this (and other) comments. I don't have a problem with using seconds but if I gave you that impression I apologise. I also didn't realise I was being such a pain and that you were such an expert. Again I apologise for offering advice and needlessly pointing out your logic errors in prior code. From what you've now said, contrary to your posts on the first page of this thread, you did not want, nor need any feedback or assistance and so I'll bow out of this thread and leave you to it.
 
motorSteps = fabs (gear_ratio_top_array[gearratioindex]*Microsteps*StepsPerRevolution)/gear_ratio_bottom_array[gearratioindex];

......

stepsperdiv = (motorSteps / num_divisions);
stepsperdivv = round (stepsperdiv * (cur_pos-1) ) ;
stepsperdiv = round (stepsperdiv * cur_pos ) ;
stepsperdiv_d = stepsperdiv - stepsperdivv + 1 ;



I'm using "fabs()" function..
I solved the floating point error by remembering the previous moved step when calculating, calculating the step to move this time, and re-inserting the amount of the difference.
 

Latest posts

Back
Top