Gコードプログラムから、CADの点群を生成する。
円弧補完も点群で表現したい。
Contents
GコードとCAD モデルを比較したいときに、GコードのままではCAD 上に読み込めないので、XYZ の羅列に変換して、点群として読み込みたい。
CAM で計算した加工経路
Gコード出力したデータから生成した点群
最後に「とりあえずの完成品」があります。
今のところG17 、G18、G19 平面への対応は、座標を計算する際に垂直方向の座標軸の値と、水平方向の座標軸の値をそれぞれ割り当てる方法にしています。
基本的な座標系。
平面にあわせて、マッピングする値を変更。「v」が垂直方向、「h」には水平方向の軸を割り当てます。
# x-y i-j
[double]$v1 = $y1;
[double]$h1 = $x1;
[double]$v2 = $y2;
[double]$h2 = $x2;
[double]$vc = $j1;
[double]$hc = $i1;
G18 みたいに正面に垂直方向が奥に向かっている場合、時計回り、反時計回りを反転させます。
switch ($mode) {
17 { [double]$incr = $i ; }
18 { [double]$incr = $i *-1 ; }
19 { [double]$incr = $i ; }
Default { [double]$incr = $i ; }
}
旋盤の場合など、軸の構成から向きを考えて調整します。
ザックリな流れ
- Gコードを一行ずつ読み込む。
- 「XYZ」いずれかの文字列があったら、その値を点群ファイルに書き出す。
- モーダルに対応するため、抜き取る時に出現していない座標に関しては、直前の値を流用する。
- 「G2」「G3」があったら、その値を抜き取り、円周上の点を計算して点群ファイル書き出す。
「XYZ」いずれかの文字列があったら、その値を点群ファイルに書き出す。
Get-Content でファイルを取得して、ForEach-Object で一行ずつ処理する。
正規表現でX、Y、Z のいずれかを検索し、ヒットしたら値を抜き出す。
値が抜き出せなかった場合は、上書きされていない値が書き出される。
Get-Content -Path $path | ForEach-Object{
#-?(\d|\d+)?\.(\d+)?
if(($_ -match '[X]-?(\d|\d+)?\.(\d+)?|[Y]-?(\d|\d+)?\.(\d+)?|[Z]-?(\d|\d+)?\.(\d+)?')){
# X-AXIS
if(($_ -match '[X]-?(\d|\d+)?\.(\d+)?')){
$X = $Matches[0];
$gen_x = [string]($X.Substring(1,$X.length-1)/$type);
}else{
$gen_x = [string]($X.Substring(1,$X.length-1)/$type);
}
}
}
「G2」「G3」があったら、その値を抜き取り、円周上の点を計算して点群ファイル書き出す。
- 前提として、
- 円弧補完は180度ごとに分割されています。
- IJK の値はインクリメントで記述されています。
G2、G3 があったら~については、上記の応用でこんな感じに検索しています。
同時にXYZ と同じ要領でIJK(円弧の中心へのオフセット値)の値も取得しています。
#G2-G3
if(($_ -match '[G][0]?[3|2]')){
if($_ -match '[G]\d?[2]'){ $G = 2 }
if($_ -match '[G]\d?[3]'){ $G = 3 }
円弧補完の点群については、別の関数「mode_g2」を作り、そっちに渡しています。
円弧補完の点群を計算する手順
円の中心座標を計算する
円弧補完の始点の座標からIJK の値を引きます。
G2、G3 が指定しているのは終点なので、その前の座標値をが始点になります。
(円弧補完のコードを読んで、関数に渡すときに、直前の値も一緒に渡しておきます。)
円の半径( r )を計算する。
IJK の有効な値から半径を求めます。
三角関数で底辺と高さから斜辺の長さを求めるやつです。
[double]$r = [Math]::Sqrt([Math]::Pow($I1,2) + [Math]::Pow($J1,2));
r * sinθ 、 r * cosθ で円周上の点を計算して、円の中心座標とあわせる。
計算した値を単純に足せば、いい感じにマージされます。
Y 方向についてはsinθ を計算した時の引数がプラスかマイナスかで指定できますが、cosθ についてはプラスもマイナスも同じになるので、X方向がマイナスの場合は反転するまでラジアンを増分するようにして調整しています。
if( $I1 -gt 0 ){
$arc_sin = $arc_sin + (([math]::Asin(1)-$arc_sin)*2);
Write-Output "arc2 :"
Write-Output $arc_sin;
}
円弧補完の終点まで計算をループする
何回ラジアンを増分しながらr * sinθ 、 r * cosθ を求める。
円弧の中心角を計算しておき、その大きさ分、計算を繰り返すようにしています。
円弧の中心角の計算
始点と終点から弦の長さを求め、弦長と半径から中心角を計算しています。
(180度の円弧の場合、Atan の計算が失敗するので、少し控えた値を渡しています。)
# 中心角を計算する
[double]$x3 = [math]::Abs($x1-$x2);
[double]$y3 = [math]::Abs($y1-$y2);
[double]$dis_xy = [Math]::Sqrt([Math]::Pow($x3,2) + [Math]::Pow($y3,2));
[double]$dis_xy_2r = $dis_xy / (2*$r) ;
[double]$dis_xy_2r_asin_2 = 2 * [math]::Asin($dis_xy_2r-0.0001);
[double]$anser = $dis_xy_2r_asin_2 * (180/[math]::PI);
ループを以下のように指定。
(ちょっと手前で止まるように0.1 控えた値を指定しています。)
for( $i=0.1; $i -lt ($dis_xy_2r_asin_2 - 0.1); $i+=0.1 ){
暫定の完成品
function test {
param(
[int]$type = 1
);
# params
$X='X0';
$Y='Y0';
$Z='Z0';
# g-code file
# $path = ".\test\GAIKEI-ARA.MIN";
$path = (Read-Host "Enter GCODE-File Path..");
# table files
$target = "test.pts";
Set-Content -Path $target -Value "";
Get-Content -Path $path | ForEach-Object{
#-?(\d|\d+)?\.(\d+)?
if(($_ -match '[X]-?(\d|\d+)?\.(\d+)?|[Y]-?(\d|\d+)?\.(\d+)?|[Z]-?(\d|\d+)?\.(\d+)?')){
# X-AXIS
if(($_ -match '[X]-?(\d|\d+)?\.(\d+)?')){
$X = $Matches[0];
$gen_x = [string]($X.Substring(1,$X.length-1)/$type);
}else{
$gen_x = [string]($X.Substring(1,$X.length-1)/$type);
}
# Y-AXIS
if(($_ -match '[Y]-?(\d|\d+)?\.(\d+)?')){
$Y = $Matches[0];
$gen_y = [string]($Y.Substring(1,$Y.length-1));
}else{
$gen_y = [string]($Y.Substring(1,$Y.length-1));
}
# Z-AXIS
if(($_ -match '[Z]-?(\d|\d+)?\.(\d+)?')){
$Z = $Matches[0];
$gen_z = [string]$Z.Substring(1,$Z.length-1);
}else{
$gen_z = [string]$Z.Substring(1,$Z.length-1);
}
# Write-host $gen_X;
# Write-host $gen_Y;
# Write-host $gen_Z;
#G2-G3
if(($_ -match '[G][0]?[3|2]')){
if($_ -match '[G]\d?[2]'){ $G = 2 }
if($_ -match '[G]\d?[3]'){ $G = 3 }
$i1 = 9999999;
$j1 = 9999999;
$k1 = 9999999;
if(($_ -match '[I]-?(\d|\d+)?\.(\d+)?')){
$i1 = $Matches[0];
$i1 = [double]$i1.Substring(1,$i1.length-1);
}
if(($_ -match '[J]-?(\d|\d+)?\.(\d+)?')){
$j1 = $Matches[0];
$j1 = [double]$j1.Substring(1,$j1.length-1);
}
if(($_ -match '[K]-?(\d|\d+)?\.(\d+)?')){
$k1 = $Matches[0];
$k1 = [double]$k1.Substring(1,$k1.length-1);
}
mode_g2 -g $g -target $target -x1 $pre_X -y1 $pre_y -z1 $pre_z -x2 $gen_X -y2 $gen_y -z2 $gen_z -i1 $i1 -j1 $j1 -k1 $k1;
}
$gen_XYZ = $gen_x + " " + $gen_y + " " + $gen_z ;
Write-host $gen_XYZ;
add-Content -Path $target -Value $gen_xyz;
$pre_x = [double]$gen_X;
$pre_y = [double]$gen_Y;
$pre_z = [double]$gen_Z;
}
}
}
function mode_g2{
# mode_g2 -target -x1 -y1 -z1 -x2 -y2 -z2 -i1 -j1 -k1
param (
# レコード
[int]$rec,
[string]$target,
[int]$g,
# 座標値
# 開始点
[double]$x1,
[double]$y1,
[double]$z1,
# 終了点
[double]$x2,
[double]$y2,
[double]$z2,
# 中心への距離(開始点に対してインクリメント指定)
[double]$I1,
[double]$J1,
[double]$K1
# model
);
$logtx = @("","","","","","","","","","","");
$logtx[0] = "g:" + $g;
$logtx[1] = "XYZ1:"+ $x1 +","+ $y1 +","+ $z1;
$logtx[2] = "XYZ2:"+ $x2 +","+ $y2 +","+ $z2;
$logtx[3] = "IJK:" + $i1 +","+ $j1 +","+ $k1;
write-output "----------------------------------->";
write-output $logtx[0..3];
write-output "----------------------------------->";
# 平面の判定
if($i1 -eq 9999999){
[int]$mode = 19;
# y-z j-k
[double]$v1 = $z1;
[double]$h1 = $y1;
[double]$v2 = $z2;
[double]$h2 = $y2;
[double]$vc = $k1;
[double]$hc = $j1;
}
if($j1 -eq 9999999){
[int]$mode = 18;
# x-z i-k
[double]$v1 = $z1;
[double]$h1 = $x1;
[double]$v2 = $z2;
[double]$h2 = $x2;
[double]$vc = $k1;
[double]$hc = $i1;
}
if($k1 -eq 9999999){
[int]$mode = 17;
# x-y i-j
[double]$v1 = $y1;
[double]$h1 = $x1;
[double]$v2 = $y2;
[double]$h2 = $x2;
[double]$vc = $j1;
[double]$hc = $i1;
}
$logtx = @("","","","","","","","","","","");
$logtx[0] = " mode:" + $mode;
$logtx[1] = "vh-1:"+ $v1 +","+ $h1 ;
$logtx[2] = "vh-2:"+ $v2 +","+ $h2 ;
$logtx[3] = "vh-c:" + $vc +","+ $hc ;
write-output $logtx[0..3];
write-output "----------------------------------->";
# 円の中心座標の計算
[double]$v3 = $v1 + $vc;
[double]$h3 = $h1 + $hc;
$logtx = @("","","","","","","","","","","");
$logtx[0] = "pos(center):" + $v3 + "," + $h3;
write-output $logtx[0];
write-output "----------------------------------->";
# 半径値を計算する。
[double]$r = [Math]::Sqrt([Math]::Pow($vc,2) + [Math]::Pow($hc,2));
#[double]$r = [Math]::Round($r,6);
# 中心角を計算する
[double]$x3 = [math]::Abs($v1-$v2);
[double]$y3 = [math]::Abs($h1-$h2);
[double]$dis_xy = [Math]::Sqrt([Math]::Pow($x3,2) + [Math]::Pow($y3,2));
[double]$dis_xy_2r = $dis_xy / (2*$r) ;
[double]$dis_xy_2r_asin_2 = 2 * [math]::Asin($dis_xy_2r-0.0001);
[double]$anser = $dis_xy_2r_asin_2 * (180/[math]::PI);
$logtx = @("","","","","","","","","","","");
$logtx[0] = "distance_xy --> gentyou:" + $dis_xy;
$logtx[1] = "gentyou/2R:" + $dis_xy_2r;
$logtx[2] = "gen-arcsin:" + $dis_xy_2r_asin_2;
$logtx[3] = "anser (unit angle):" + $anser;
Write-Output $logtx[0..3];
write-output "----------------------------------->";
# アークサインを計算する。$J の値を単位円に調整し、正負を反転させる。
# 向きの関係
$arc_sin = ([math]::Asin(($vc/$r)))*-1;
$logtx = @("","","","","","","","","","","");
$logtx[0] = "arcsin:" + $arc_sin;
Write-Output $logtx[0];
#
if( $hc -gt 0 ){
$arc_sin = $arc_sin + (([math]::Asin(1)-$arc_sin)*2);
$logtx = @("","","","","","","","","","","");
$logtx[0] = "arcsin2:" + $arc_sin;
Write-Output $logtx[0];
}
#座標値を計算する。
for( $i=0.1; $i -lt ($dis_xy_2r_asin_2 - 0.1); $i+=0.1 ){
if( $g -eq 3 ){
[double]$incr = $i ;
}else{
# G2 の場合減算にする(時計回り)
[double]$incr = $i*-1 ;
}
[double]$addv = $v3 + ([Math]::sin($arc_sin + $incr) *$r);
[double]$addh = $h3 + ([Math]::cos($arc_sin + $incr) *$r);
$logtx = @("","","","","","","","","","","");
$logtx[0] = "incr:" + $incr + " r:" + $r;
$logtx[1] = "vertical-c:" + $v3 + " arc_sin:" + $arc_sin + " A:" + ([Math]::sin($arc_sin + $i) *$r);
$logtx[2] = "horizon-c:" + $h3 + " arc_sin:" + $arc_sin + " A:" + ([Math]::cos($arc_sin + $i) *$r);
Write-Output $logtx[0..2]
write-output "----------------------------------->";
switch ( $mode ) {
17{
# mode-17 x-y i-j
[string]$res = [string]$addh + " " + [string]$addv + " " + [string]$z2;
}
18{
# mode-18 x-z i-k
[string]$res = [string]$addh + " " + [string]$y2 + " " + [string]$addv;
}
19{
# mode-19 y-z j-k
[string]$res = [string]$x2 + " " + [string]$addh + " " + [string]$addv;
}
Default { [string]$res = [string]$addh + " " + [string]$addv + " " + [string]$z2; }
}
#if( $addx -gt $x2 ){
#if( $addx -lt $x2 ){
Write-Host $res;
add-Content -Path $target -Value $res;
#}
}
}