Encoder velocities and index signal reading

More
19 Sep 2019 22:09 #145633 by blazini36
I like the idea of the modulus, while a simple version solves my problem of seeing encoder counts it still requires quite a bit of hal logic to produce a usable result so I'm going to complicate the component quite a bit to simplify the rest of the program. I spoke to my friend about this and it doesn't seem that it'll be much of a thing for him.

I'm going to whip up a block diagram for it. One thing I'm not certain of is I like to deal with everything as positions rather than counts. In order to apply a modulus operation it must be done on an integer right? Thinking the component is going to have to accept a position as float input and a "requested position" as float input (the expected remainder of the modulus which will behave similar to a comparator. Assuming that's the case it's going to require 2 float to integer conversions. Curious if that's any sort of a performance hit I should be concerned about. I wouldn't think it's something I'd worry about since I have all sorts of that going on in the current hal file anyway.

Please Log in or Create an account to join the conversation.

More
19 Sep 2019 23:23 #145636 by andypugh
You can work in float if you want, but be careful that you don't run out of numerical resolution. How long does your encoder run for between resets?

HAL float pins are double precision, approx 15 decimal places resolution, and that means that 100000000000000 == 100000000000001

If there is no chance of getting that far then it's OK.

(The actual maths is more complicated than I describe here, see for example stackoverflow.com/questions/9999221/doub...ision-decimal-places )

If you work in 64-but int there is really no danger of this sort of problem.

Please Log in or Create an account to join the conversation.

More
19 Sep 2019 23:31 - 19 Sep 2019 23:46 #145638 by blazini36
Nevermind....fixing
Attachments:
Last edit: 19 Sep 2019 23:46 by blazini36.

Please Log in or Create an account to join the conversation.

More
20 Sep 2019 02:22 - 20 Sep 2019 02:24 #145645 by blazini36

You can work in float if you want, but be careful that you don't run out of numerical resolution. How long does your encoder run for between resets?

HAL float pins are double precision, approx 15 decimal places resolution, and that means that 100000000000000 == 100000000000001

If there is no chance of getting that far then it's OK.

(The actual maths is more complicated than I describe here, see for example stackoverflow.com/questions/9999221/doub...ision-decimal-places )

If you work in 64-but int there is really no danger of this sort of problem.


Is it a thing to impose limits on hal input pins? I don't expect to count past 280.000 with only 3 digit precision being necessary. The divisor pin would be a max of 10 in real use. If possible I'd limit the pin "event-position" pin to 99.999 and the Repeat-multiple pin to 99 then the max length possible for the encoder to run off and count positions to would convert to 9899901 I suppose. The encoder position is to be reset when the trigger pin is output.

Makes more sense looking at this, or maybe not. I'll have to stare at this for an hour tomorrow to see if I didn't go overboard with this, but at the moment I gave myself a headache. Besides the fact that the float-int conversions may not all be necessary which I'm sure my friend can figure out, I think I've considered everything. It seemed easier, then I got to it and it got a bit more complicated than I expected.

Attachments:
Last edit: 20 Sep 2019 02:24 by blazini36.

Please Log in or Create an account to join the conversation.

More
20 Sep 2019 09:31 #145653 by andypugh
The problem I described is just in the nature of double-precision floating point numbers.

It has just occurred to me that you might be able to mis-use the "bldc" component for this purpose. (in "qiB" mode. linuxcnc.org/docs/2.7/html/man/man9/bldc.9.html )

But a custom component seems more elegant and adaptable.

Please Log in or Create an account to join the conversation.

More
21 Sep 2019 00:16 #145725 by blazini36
As long as my logic is sound, I doubt this will be a problem for my friend to get going. Unfortunately free time is probably every projects worst enemy.

Please Log in or Create an account to join the conversation.

More
21 Sep 2019 02:11 #145728 by andypugh
Unusually, this probably really is a very quick thing for someone familiar with C to do.

Generally coding puzzles are always bigger than expected, but with a good spec from you this probably is only a dozen lines of code.

Tips for your coder friend:

Your code will be called automatically ever 1mS. It can't wait, it has to run straight through ever time.

static state variables are a good way to handle waiting, and context-dependent behaviour. Many comps use a state machine structure.

The comp file format plays strange games with macros. You might be surprised by the bracket styles needed.

Please Log in or Create an account to join the conversation.

More
21 Sep 2019 07:12 - 21 Sep 2019 07:15 #145737 by rodw
Looking at your logic, I kinda think that converting to integers is not really necessary becasue C has it covered.
you can just use the fmod(a,b) function to calculate the modulus of two floating point numbers (where a is divided by b in the example)
This will result in a floating point number though. If you wanted a whole number there are two options:
Round up or down to the nearest whole number using round() or;
truncate to the whole number value (eg always round down) with trunc()

The only thing you need to be careful of is that you can't really test for equality with any floating point number. Instead you test for precision. Something like this:
if(fabs(a-b) < 0.00001) {  
   //do something
}
fabs() returns the absolute value of a floating point number (eg gets rid of the sign)
It depends how precise you want to be but there is no point testing for a value that is smaller than the machine's resolution.

Finally, let me say inputting a value in nano seconds makes no sense when the servo thread generally only fires every millisecond so LinuxCNC can't see time periods below 1 millisecond. You can run a faster servo thread if your PC hardware is good enough but I thought that going past 4 kHz was problematic.

So once your friend gets to code this, it will keep getting simpler..

PS What would Gutenberg say if he saw this. Can you imagine inventing a technology today that remained unchanged for 350 years like he did!
Last edit: 21 Sep 2019 07:15 by rodw.

Please Log in or Create an account to join the conversation.

More
21 Sep 2019 15:14 #145754 by blazini36

Finally, let me say inputting a value in nano seconds makes no sense when the servo thread generally only fires every millisecond so LinuxCNC can't see time periods below 1 millisecond. You can run a faster servo thread if your PC hardware is good enough but I thought that going past 4 kHz was problematic.


You're right, It did seem necessary to add a width though since otherwise the pin would only hold a true value for one servo period, msec float would probably be more appropriate. The integer conversions were there just in case it is what was necessary, not that it really is. Kind of a moot point because this is what he came back with:
component modular_position;

/**
 * Input pins 
 */
pin in float current_pos;
pin in unsigned repeat_multiple;
pin in float repeat_length;
pin in float event_pos;

/** 
 * Output pin 
 */
pin out bit event_trigger;

function _;

license "GPL";
;;

// #include<stdio.h>

FUNCTION(_)
{
    double destination = repeat_multiple * repeat_length + event_pos;
    event_trigger = (current_pos >= destination);
}

Lol now I'm a bit miffed, I can't find any reason why that won't work other than maybe some LinuxCNC semantics and it probably should have the output-width pin. I feel like it shouldn't be this easy but it looks like it probably is.

Please Log in or Create an account to join the conversation.

More
21 Sep 2019 19:45 - 21 Sep 2019 19:46 #145782 by rodw
I'm not sure if this will help. Try
    double destination = (double)repeat_multiple * repeat_length + event_pos;

C is a typed language so it is not usually valid to mix types (unsigned and double) in a calculation so you need to use a cast to explicitly tell C to convert that number to a double before using it.

EDIT: So the code will compile but I would expect to generate a compiler warning and one should always treat warnings as if it was an error if you are programming defensively.
Last edit: 21 Sep 2019 19:46 by rodw.

Please Log in or Create an account to join the conversation.

Time to create page: 0.101 seconds
Powered by Kunena Forum