Question on GCODE execution frequency

05 Mar 2021 08:51 #201084 by amoser

Dear All,

I have last year repaired an old CNC with a broken controller to linuxCNC + Mesa and it was easier than anticipated. And it runs really well. Thanks a lot for all your work developing linuxCNC!

I am now building another machine (I call it “splicer”). It’s a CNC controlled camera and does visual sampling. It’s intended use is to make post-linear perspective photography. I know, not really what LinuxCNC was intended for but it actually works well.

Splicer consists of three parts, camera, sample mover and controller

  1. The camera is a monochrome line scan camera and two axis of motion. One (U) is for moving a RGBA filter in front of the sensor to do trichromatic full color images. The second camera axis (V) is for autofocus.
  2. The sample mover moves an object in coordinated movements in front of the camera. It’s currently 3 axis, X / Y / C (rotation around Z). Planned for the future is also Z and possibly B (rotation around Y axis).
  3. The controller is two computers. One running Windows, with a FPGA capture card receiving the image data from the line scan sensor. And one running LinuxCNC doing all the real-time motion and camera line triggering in coordination with the sample moves.

The “CAM” part I do in Blender. I wrote a simple python script that translates an animation in Blender to very stupid slow GCode so that I can do the animation work in Blender and then let it run for real on splicer.

And here comes the issue / question:

Linux CNC interprets a line of Gcode > does the move (of a few 1/100th of mm). > triggers a line recording. > Does the next move > triggers the next line. And so on.

The camera is a high speed camera with very short exposure times and in need of a lot of light. I can set the exposure time (per line) of my camera between 1.75 to 3270 µs. The example below read ~45000lx at the sample. (1* 300w led + 2* ~100w led lights). It starts to become unpractical to add more light.

At an exposure time of 3200µs, I can have a max. line frequency of ~300hz.

But if there are no big moves in the GCode. LinuxCNC will read more than 300 lines / s. (I know this is great for normal machines :P - but it’s an issue for me - this will overload the image acquisition.

Is there a way to limit the lines / s of gcode interpreted in linuxCNC?

Workaround A (tested):
In the blender python script (CAM-part) I calculate where unscientifically the delta of the current move and if it falls below a threshold, I add a G04 5ms dwell.
> works more or less.
> makes everything slow as I need to be overly conservative with my threshold.
> introduces vibration

Workaround B (in progress):
I realised yesterday, that there is G61. In the blender python script I can calculate a simplified time a move will need per axis. (Using the per axis acceleration / max velocity). If this time is below 3.5ms I can add a dwell.
> might be more efficient.
> will introduce vibrations as well.

Do you have any other ideas how to solve the issue?

Thanks a lot & have a great day,

For reference, a the beginning of a gcode file:
(© Florian Amoser, 2021)
(This is machine specific gcode for SPLICER)
(linenumbers: 11500)
G90 G17
G0 U0
G01 F5000
G01 X187.758 Y0.0 C0.18 V52.5 M62 P0
G04 P0.004
G01 X187.77 Y0.0 C0.18 V52.5 M63 P0
G04 P0.004
G01 X187.783 Y0.0 C0.19 V52.5 M62 P0
G04 P0.004
G01 X187.795 Y0.0 C0.19 V52.5 M63 P0
G04 P0.004

And an image of splicer:

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

05 Mar 2021 09:34 #201087 by andypugh
A simple answer inside your current structure might be to use G93 inverse time mode. Then every line of G-code has a parameter saying how long the move should take. (it has units of 1/seconds for historical reasons)

But perhaps you are doing it all wrong?

I will assume that the FPGA is hardware-triggered and there is no synchronisation problem there.

You mention vibration being a problem, so I assume that means that you do not want the motion to stop at every photo point? This would be best for image sharpness, as (in theory) you are not photographing a moving object. (But in practice you are photographing a wobbling object)

If the camera definitely takes an image every time the hardware is triggered then I would suggest taking the same approach as rigid threading in LinuxCNC: Move the axes smoothly and continuously, and generate a strobe output in HAL independent of the motion.

In this scheme your G-code would be much simpler, just long coordinated moves in XYCV. You would set the overall feed-rate to control the exposure time.

I would probably write a custom HAL component to calculate the trigger points from position inputs, but it could be done by adding the axis positions together with a sum2 (noting that the inputs each have a multiplier that could be used to scale rotary motions) then converting the floating-point position sum to unsigned-32 using conv_float_u32 and then using the lowest (or second lowest) bit from bitslice as a distance-proportional trigger output.

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

05 Mar 2021 10:23 #201093 by amoser
Dear Andy,

I will look into G93, I was not aware of this. (cnc noob here).
It sounds like a solution as I can slow execution down.

No there is no problem there. I was not precise enough. The issue is that a second line get's triggered by the controller while the first line ist still being exposed. = line trigger to line trigger delay shorter than exposure time. And I need to prevent this from the controller side.

The sensor is 8k*1px. An square image is about 8000 lines wide. Stopping at every position makes the time needed to acquire an image too slow. Lot's of small steps with stops are an issue doe to the wobble. Photographing the objet in motion is less so. As the delta displacement during the exposure time is often smaller than a pixel. Or at least it's less disturbing visually.

Rigid Threading / Custom HAL component:
You are absolutely right on this. I know that this would technically be the right approach, will look into it how I can do this.
The issue (without yet researching it atm more in detail) is that the trigger frequency might need to change during even a linear move. While reading it again: I am probably wrong. This sounds like the possible approach. Fixing line acquisition frequency and calculating federate accordingly to the needed displacement. Will look into this.
I will also look into the custom HAL component approach. If I understand right, it's similar to my Option B, but properly solved on the controller side instead of the CAM side.

Thanks a lot for the ultra quick feedback!
The following user(s) said Thank You: tommylight

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

07 Mar 2021 00:38 #201236 by andypugh
I wrote the HAL component. How to compile and install it is documented here:

But basically save this in a file called "shutter.comp" and then run the command "sudo halcompile --install shutter.comp"

It will create a HAL component that you can use just like any other.
component shutter "pulse an output after a certain distance travelled";

pin in float motor-pos-#[9] "Connect to joint.N.motor-pos-cmd";
pin in float scale-#[9] = 1 "Leave as 1 for linear, but scaled to radius for rotary";
pin in float pulse-distance = 1 "Distance to travel between pulses";
pin in signed pulse-length = 3 "number of servo cycles to keep pulse high";
pin out bit pulse;

include "rtapi_math.h";
author "andypugh";
license "GPL";

function _;


static double acc;
static double last[9];
static int t;
double d;
int i;

d = 0;

for (i = 0; i < 9; i++){
    d += pow((motor_pos(i) - last[i]) * scale(i) ,2);
    last[i] = motor_pos(i);

acc += sqrt(d);

if (acc >  pulse_distance) {
    acc -= pulse_distance * floor(acc / pulse_distance);
    t = pulse_length;
if (t > 0) {
    pulse = 1;
} else {
    pulse = 0;

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

08 Mar 2021 07:51 #201394 by amoser
Dear Andy,

Your help is very appreciated! I did not have the time yet to fully immerse myself into it. Will read into it tonight.

Reading quickly through HAL compile, this is incredible. LinuxCNC is so extremely open to accommodate custom problems.

Thank you!

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

Time to create page: 0.363 seconds
Powered by Kunena Forum