Useful Plasma Thread
Anyway, a couple of things.
Mesa THCAD-10 calibration
You don't need to worry about calibrating the Mesa THCAD as PCW has already done it for you for each individual board and applied a label to each board.
This earlier post is a component to decode the THCAD-10 data using that calibration data and has a pin to output the current volts. forum.linuxcnc.org/plasma-laser/32585-scalethcad-component.
Its tested and works well on my config.
I'm still not sure why we use the raw voltage (maybe only for display purposes) as the encoder frequency could be used without conversion.
If you grab a couple say of 48v power supplies and connect them in series, you have 96 volts and you can apply that as the input to your plasma cutters voltage divider board to check functioning. I found this useful.
Corner Lock
This thread includes a corner lock component that I have used for a long time so its proven and working. It outputs a signal to say hold the THC function forum.linuxcnc.org/plasma-laser/32658-thc-cornerlock-component
So this simply looks at the current velocity adjusted for speed override and asserts a hold signal when it falls below a set threshold say 80% of the commanded velocity.
Kerf Crossing
The attached chart shows what happens to torch voltage when crossing a kerf (data from a hal plot at 200 Mhz sample time:
So if we use a moving average, we can compare the change in voltage over this time period with the average over the last 100 readings and if it differs significantly, we hold THC behaviour. In practice however, I think a single servo period is too short to be doing the comparison with as normal hysteresis around the torch voltage set point might be enough to trigger the component from one period to the next.
Torch Sampling using Moving Average
I have not published this before so the man page might be wrong but this component calculates a moving average for BUFFSIZE readings (currently 100 but can be changed in the code) and samples the Average Torch volts when a signal from a delay component after ArcOK goes true. Its been tested enough to know it works (I think, at least I know the buffer does not overwrite other memory).
Conceptually, a moving average is very simple using a loop but in the servo thread we cannot use loops so we do some tricks separated into a separate procedure avgarcvolts().
We use pointers to read the readings into the buffer but if we sum the values and allow the buffer to fill (during the THC time delay), we subtract the oldest reading in the buffer and add the newest buffer reading. With this in mind, in a circular buffer, the oldest reading is the one in front of the current pointer position (assuming the buffer logic wraps the pointer from the last buffer position to the first automagically).
Its worth mentioning that the torch should not be sampled unless its near (say 95%) of programmed cut velocity as its possible that the trajectory planner may have reduced the cut velocity below what has been requested for a given line segment at the time you sample the volts. So that is the reason for the Case statement and the component will sit patiently in an ARMED state until this occurs.
Next Steps
My next step was to separate out the moving average into its own component so it can be used for both Kerf Crossing and Torch sampling. I think I should include the ability to create multiple instances with a different buffer size as it might be useful to have a long average and a short average (of say 5-10 readings) for different comparisons.
I also think that the THC component should be kept totally separate from the touchoff component. I'm not tested it yet, but I suspect that there would be merit in moving the THC component onto a separate slower thread (maybe at 200 Hz?) to allow time for the motor to reach its commanded position on a given adjustment before moving it again. This is just based on a lot of reading I have done about PID control and some comments from Hypertherm shared on my Spaceship Plasma Build thread.
I hope this helps.
Please Log in or Create an account to join the conversation.
On the other side, the THCAD with any Mesa board can measure the torch voltage 1000 times per second, and that is to much for what it needs to do,\.
Tommy posted while I was writing my last post. I think he confirms my thinking about keeping the actual THC component on a seperate thread where it can be running at a slower time frame (or it skips a few servo thread cycles between actions). Thanks Tommy!
Please Log in or Create an account to join the conversation.
Russian Anonimouses. Are they into the bios ? They will eat your desktop pc in one day....I just tried to boot into Linux on my desk PC but it failed for some reason and left me at the command prompt.
Thanks for your post Rod. I will investegate your diagram carefully.
I have made a short example of code for logging the program for 5 seconds with 0.1 seconds interval time.
Here off we can make multiple calculations for making the best choice for the machine by itself. User's can select type of calculation.
component Voltage_data_Position_logger "..";
description
"""
Todo
""";
author "Grotius CNC Machines";
license "GPLv2 or greater";
option singleton yes;
// Input Pins
pin in bit Enable "Enable this function";
pin in bit Do_calculation "Do your calculation";
pin in float Time_gone_by "For example 0.1 sec";
pin in float Voltage_in "For example 260 volts and changing";
pin out float Timeplus "Timeplus is one step forward on system : fperiod";
pin out bit Sha_the_bitcoins "This line is for google bot's";
// Output Pins
pin out float Perfect_value "Calcutated Perfect Output Voltage";
pin in bit Hit_the_button "Use this voltage value in your currently running program right now !! ";
// Global Variables
// 1 second 0.1 sec scale :
variable float T1; variable float T2; variable float T3; variable float T4; variable float T5;
variable float T6; variable float T7; variable float T8; variable float T9; variable float T10;
// 2 second :
variable float T11; variable float T12; variable float T13; variable float T14; variable float T15;
variable float T16; variable float T17; variable float T18; variable float T19; variable float T20;
// 3 second :
variable float T21; variable float T22; variable float T23; variable float T24; variable float T25;
variable float T26; variable float T27; variable float T28; variable float T29; variable float T30;
// 4 second :
variable float T31; variable float T32; variable float T33; variable float T34; variable float T35;
variable float T36; variable float T37; variable float T38; variable float T39; variable float T40;
variable double Time_resolution; //the time starting and counting up. The past is inluded.
variable double Timeplus; //the time when we
variable float First_second; //holds the best volt value of first second.
function _;
;;
#include "rtapi_math.h"
FUNCTION(_) {
if(Enable){
x = Time_gone_by // in this case input float 0.1 sec.
Timeplus += fperiod;
if(Timeplus = fperiod + x){T1 = Voltage_in;} // log first voltage.
if(Timeplus = fperiod + (2*x)){T2 = Voltage_in;} // log second voltage.
if(Timeplus = fperiod + (3*x)){T3 = Voltage_in;} // and so on we go.
// automate
// So we have 40 times a voltage stored in variable every 0.1 second.. That is nice !!!
// Now we can do a nice calculation's to make improvements for linuxcnc users.
//Calculation of first second is starting here :
if(Do_calculation){(First_second = ((T1 + T2 + T3 + T4 + T5 + T6 + T7 + T8 + T9 + T10) / 10);} //And expand this.
if(!Hit_the_button){;} //if you don't hit the button okey...
if(Hit_the_button){Perfect_value = Voltage_in;} // This was easy ...
if(Do_calculation){Perfect_value = ((First_second + Second_second + Thirth_second + Fourth_second + Fifth_second)/5);} // this is just like minmax.
// So we can make a nice voltage output value. We can also write a log in external files if we want to.
// Dataloggers is expensive equipment !!
}
}
@Tommy,
the 5 second's or longer can display your cutting charts. After cutting, the chart's can say if you was a good cutter or a bad cutter.
The ultimate line stay's stady. But fluctuence's have to be avoid. Kerf crossing and corner lock is one of them.
At the logging every 0.1 second. The machine can make a desicion on the past logging. Will i go this way, or wil i go for improvement? Users can select a cutting chart. I think there will be 3 charts. 3 types of calculating. I think logaritme i will also try to use for fun, if possible.
Please Log in or Create an account to join the conversation.
fperiod is not guaranteed to be exact if the thread is early or late so testing for equality is not going to work every time. you need to do a if... else if... else if ... and test for > T1, T2 etc. Steal The buffer approach using pointers I shared and see how you go. Just change the BUFFSIZE to 5000.
Please Log in or Create an account to join the conversation.
Was it a linux mint desktop environment?
So yes, why not switch to debian?
Still having russian anonimouses, switch to Kali and strike back.
I also think that the THC component should be kept totally separate from the touchoff component.
First i thought also to build in blocks, i agree.
But now i think, if the component stay's structurized, it's easy to implement. Some guy's have 1000 lines of C code.
From what i know now, the touch off procedure takes about a max of 20-25 line's of C code. This is easely to implement in the same component. When i got it finished, i will show it to you coming day's. It's hot on my to do llst.
I agree when it has no probe function included (touch off)I think he confirms my thinking about keeping the actual THC component on a seperate thread where it can be running at a slower time frame
Hmm 200 Mhz.. This diagram looks to fast to make a conclusion for me. I can't figur out what the scaling value's are, sorry.The attached chart shows what happens to torch voltage when crossing a kerf (data from a hal plot at 200 Mhz sample time:
If i can see a chart of a periode of time T versus volts V, i can imagine how the arc is responding.
Torchsample.3 is a nice piece of code. I must get a lession of c code to get as good as you !!
I will remind this, nice info. This week i will get some time to program and learn of your code examples, hopely i don't have to cook indonesian hot chicken.Steal The buffer approach using pointers I shared and see how you go. Just change the BUFFSIZE to 5000.
Please Log in or Create an account to join the conversation.
And there is no need to buy a data logger. You can use the Halsampler and sample components and log data to a file every servo thread cycle for further analysis in a spreadsheet. I captured 16000 readings of torch voltage using this method.
So I want to recapture the dV/dT data using Halsampler.
An alternative to a seperate thread is to skip a number of servo thread cycles. This is easy to do using a counter and modulo division something like
#define SKIP_PERIODS 10 // check something every 10 cycles
int counter = 0;
counter +=1;
if(!(counter % SKIP_PERIODS)){
// do something
}
Please Log in or Create an account to join the conversation.
This example helps me :
typedef enum {ONE, TWO, THREE} State_T;
State_T state = ONE;
switch(state){
case ONE:
state = TWO;
break;
case TWO:
state = THREE;
break;
case THREE:
Case3_is_working = 1;
break;
Then this one : return 1;
Sometimes is see return 0;
And when to use static variables.
Please Log in or Create an account to join the conversation.
By default variables defined in a procedure are thrown away and the memory released when you exit the function so the memory can be reused. The static modifier defines the variable in static memory so it is not thrown away and retains its value when the function is next called. You can use global variables but that is a bit messy if a procedure is the only one that needs the variable.
Procedures can optionally return a value and the type is defined in the prototype. heres a simple example that returns the sum of 2 values:
int summer(int a, int b)
{
return (a+b);
}
so you might write
answer = summer(a,b);
Butt often the return value is used to denote an error occurred.. Generally 1 for an error or 0 for valid result
say it was an error if a or be was > 100, we might return the answer by reference like this
int summer(int a, int b, int *ans)
{
if (a > 100 || b >100)
return 1;
ans = a+b;
return(0);
}
and you might call it like this:
int answer;
retval = summer(a,b, &answer);
if(retval)
printf("Invalid values passed to summer\r\n");
else
printf("answer = ' %d", answer);
Through the magic of pointers, if valid values are passed, answer will still have the correct answer!
Finally, often we don't bother with the intermediate value (retval in the example) and would often write it like this:
int answer;
if(summer(a,b, &answer));
printf("Invalid values passed to summer\r\n");
else
printf("answer = ' %d", answer);
Its up to you to decide what the error numbers are. Sometimes -1 is used. Often there will be a whole host of equates defined so different errors can be identified.
Please Log in or Create an account to join the conversation.
I have made some progress the last day's with up's and down's in C code.
Thanks, Rod, for your e-mail examples.
For example, i made 2 brand clean configurations. Started with zero code, just to be sure.
One without external offsets. This was hard to program. It's just not made
for thc function's. After spending a lot of time in that, i switched to external offset's. This was much easyer to write C code for.
The difficulty in the standard linuxcnc distibution is that making offset's and stay them in line is a little bit of hard to do with a few lines of code for a new C programmer. Maybe over a few years i will say, yes i missed something in that time, now it's easy.
Today cutted a sample for my wife with the new C code. After tuning a few gui parameters, it cut's better then Mach3 windows.
But it's a long way to the top. At the picture my nozzle was damaged, so i am not satisfied about the holes.
I would like to make contact coming time with the Russian cnc forum that has made the Inkscape plugin.
My investegation is import a dxf right into the gremlin screen as g-code with inkscape only loaded as blockchain.
My C code language is improved a little bit, With compiling i get less errors, because you know how to use the language.
Here a example code that i used with succes, it's still basic in the eye of the C-coder,
The code is only related to the probe function :
component THC2 "Torch Height Control for stepper and servo machines, compatible with external offset branche";
description
"""
Todo
""";
author "Grotius CNC Machines";
license "GPLv2 or greater";
option singleton yes;
// Input Pins
pin in bit Enable "Enable component";
pin out bit Reset_offsets "Reset offsets to orginal condition when component is not enable";
pin in float Zpos_in "";
pin out float Zpos_out "";
pin in float Travelheight "Z axis travelheigt in";
pin in float Cutheight "Z axis cut height in";
pin out float Maxspeed "Z axis speed out 0 to 100, for info only";
pin out float ProbeSpeed "Z axis probing speed";
pin out float Speed "Z axis current speed, for info only";
pin in float Piercespeed "Z axis pierce speed in 0 to 100.";
pin in float Piercedelay "Z axis pierce delay time in seconds";
pin out bit Piercetime_reached "Piercetime reached";
pin in float Up_down_resolution "When Torch up, then correction 0.1mm or 1mm resolution";
pin in float Axis_z_eoffset "Connectod to external offsets z real time current z axis position input";
pin in float Pierceheight "the pierce height value in mm";
pin out float Offset "Z axis Offset command to external offsets, the z axis is moving to this offset when set, even in pause";
pin in bit Torch_on_in "Connected to spindle-cw";
pin in bit Probe_enable "Connected to user interface button";
pin out bit Probe_trigger "If probe is triggered this pin becomes high";
pin out bit Cutting_trigger "At cutheight and cutting";
pin in float Probe_search_limit "Connected to user interface input, z axis probe end limit. For example Z -10 = probing to max Z-10.";
pin in float Probe_switch_offset "Probe sensor switch correction value, positive z-value";
pin out float Zpos_probe "Z value when probe was triggered";
pin in bit Arc_ok_in "Parport connections in 12";
pin in bit Torch_up "Parport connections in 13";
pin in bit Torch_down "Parport connections in 11";
pin in bit Probe_in "Parport connections in 15";
pin out bit Torch_on_out "Parport connections out 17";
pin out bit Pause_machine "Connect to motion.feed-hold-inhibited";
pin out float Zpos_cmd_out ;
variable double time;
function _;
;;
#include "rtapi_math.h"
#include "stdlib.h"
#include "stdio.h"
FUNCTION(_) {
Zpos_out = Zpos_in;
if(!Enable){
Reset_offsets = 1;
Offset = 0;
Probe_trigger = 0;
Torch_on_out = 0;
Piercetime_reached = 0;
time = 0;
Pause_machine = 0;
}
if(Enable){
if(!Torch_on_in){
Torch_on_out = 0;
Offset = Travelheight;
Cutting_trigger = 0;
}
if(Torch_on_out){time += fperiod;}
if(time >= Piercedelay){ Piercetime_reached = 1;}
if(!Torch_on_in){time = 0; Piercetime_reached = 0;}
Reset_offsets = 0;
if(Probe_enable){
if(!Torch_on_in){
Probe_trigger = 0;
Pause_machine = 0;
Piercetime_reached = 0;
Cutting_trigger = 0;
Offset = Travelheight;
}
if(Torch_on_in && !Probe_in && !Probe_trigger){
Offset = Probe_search_limit;
Pause_machine = 1;
}
if(Torch_on_in && Probe_in){
Zpos_probe = Axis_z_eoffset;
Probe_trigger = 1;
Pause_machine = 1;
}
if(Torch_on_in && Probe_trigger){
Offset = Zpos_probe + Pierceheight + Probe_switch_offset;
Pause_machine = 1;
}
if(Torch_on_in && Probe_trigger && ((int)Offset == (int)Axis_z_eoffset) ){ // moving to pierceheight, if at height, ok.
Torch_on_out = 1;
Pause_machine = 1;
}
if(Torch_on_out && Piercetime_reached){
Offset = Zpos_probe + Cutheight + Probe_switch_offset;
Pause_machine = 1;
}
if(Torch_on_in && Piercetime_reached && ((int)Offset == (int)Axis_z_eoffset) ){ // add arc ok signal.
Cutting_trigger = 1;
Pause_machine = 0;
}
if(Torch_up && Torch_on_out && Cutting_trigger && (Axis_z_eoffset <= Travelheight) ){
Offset = Axis_z_eoffset + Up_down_resolution ;
Pause_machine = 0;
}
if(Torch_down && Torch_on_out && Cutting_trigger && (Axis_z_eoffset >= Probe_search_limit) ){
Offset = Axis_z_eoffset - Up_down_resolution ;
Pause_machine = 0;
}
if(!Torch_down && !Torch_up && Torch_on_out && Cutting_trigger){
Offset = Axis_z_eoffset;
Pause_machine = 0;
}
}
}
}
// Code Example Library :
// if(Simulate_arc_ok_in){Arc_ok_led = 1;} else {Arc_ok_led = 0;}
//
//time += fperiod;
//if(Torch_on_in){time += fperiod;}
//if(time >= Piercedelay){ Piercetime_reached = 1;}
//if(!Torch_on_in){time = 0; Piercetime_reached = 0;}
The C code example is only for using the Probe function. This was the most difficult function to make. So i started with a
working probe function in C. The normal code without probe i made and is much easer to write.
So we are at the good way. I need to save the linux screen parameters automaticly. Maybe someone has an idea?
Yes, A difficult item when coding:
(int)Offset == (int)Axis_z_eoffset)
If you want to go to zero, check zero, and current z axis height value is : 0.0025
You have a big problem if you are using float variables.
So at the moment i map the z axis value at zero or a certain point. I used an integer value wich is : 0 or 1 or 2.
This solves many issues. For example. Are we on pierce height? Are we on cutheight? If we almost get there the integer will say
okey it's true. But solving little axis feedback and command values differences are in C coded hard to make straight.
Please Log in or Create an account to join the conversation.