レーザー加工の依頼はこちら

 Order laser cut or engrave

宮のレーザー加工所

レーザー加工機・3Dプリンタ・卓上旋盤・卓上フライスなどなど。。趣味で集めた機械での遊びを発信するブログ。工作機械全般の話になってきたので題名変更しました。

Milling Machine G-CODE Backlash Compensation Tool

We have created a G-CODE backlash compensation tool for milling machines similar to the previously published G-CODE backlash compensation for lathes in Fusion360.

 


It takes the form of a G-CODE created in PostScript for GRBL in Fusion360 and processes 

The direction of movement of the cutter to the machining position is also specified.

The X and Y axes are moved in the plus direction, and the Z axis is moved in the minus direction (spindle down) to match.

When CALL.py is executed, a file selection screen will appear. Select the file to be processed.

When the process is complete, a file is created with NBC appended to the file name.

Here is an example of processing. If you process the code for drawing a circle, you will see that a correction movement is added at the point where each axis changes direction. This motion moves the motor, but not the table, so the processing is performed without any actual displacement.

 

フライス盤用G-CODEバックラッシュ補正ツール

以前に作成したFusion360の旋盤用G-CODEバックラッシュ補正と同じようにフライス盤用のG-CODEバックラッシュ補正ツールを作成しました。

 

Fusion360のGRBL用PostScriptで作ったG-CODEを加工する形をとっています。

動作にはPythonの実行環境が必要です。作成時はPython3.9を使いました。

ファイルは下記のリンクからZIP形式でダウンロードできます。

DIST.zip - Google ドライブ

 

解凍すると8個のpyファイルが出てきます。処理が複雑だったので、ステップごとに分けて作成しました。各ステップごとに実行する事も可能ですが、CALL.pyで一括して加工します。

使う前にお使いの機械のバックラッシュ量を指定します。

07_Direction.pyの冒頭に下記の部分があります。

CompVの配列にX,Y,Z軸のバックラッシュ量を測定して記入してください。

加工位置までの刃物の移動方向にも指定があります。

X,Y軸はプラス方向、Z軸はマイナス方向(主軸下げ)に動かして合わせます。

 

CALL.pyを実行するとファイルの選択画面が出てきます。処理対象のファイルを選んでください。

処理が完了するとファイル名にNBCと追記されたファイルが作られます。

処理例です。円を描くコードを処理すると、各軸の向きが変わる所で補正分の動作が追加されていることが分かります。この動作はモーターは動きますが、テーブルは動かないので、実際にはずれる事無く加工を行います。

 

コンビ ハイローチェア スイング不具合の修理

ハイローチェアのスイング機能が動かなくなったので分解、確認する事にしました。中古で手に入れて、3人に使ったので十分頑張ってくれましたが、更にお譲りする事になったので掃除を兼ねたメンテナンスです。

 

座面の前側に4本、後ろ側に2本ネジがあるので外します。後ろはカバーが付いており、外します。カバーは樹脂爪なので少し慎重に外します。

f:id:knob_create:20220730150325j:image

f:id:knob_create:20220730150328j:image
f:id:knob_create:20220730150331j:image

ネジを外すと座面ユニットを持ち上げて外せるようになります。座面ユニットはリクライニング機能までを受け持つ仕組みでした。座面を外すとスイング機構が現れます。白い枠がスライドします。中の機構はおもにアクチュエーターです。中心にあるのが電磁石だと思います。鉄の塊を引き寄せて揺れを作り出しています。動作音が静かなのも納得ですね。

f:id:knob_create:20220730150708j:image

次に後ろ側のカバーを外します。ネジ4本で固定されています。

f:id:knob_create:20220730151235j:image
f:id:knob_create:20220730151239j:image

平行に並んでいる金具と中央のシャフトを外すと、スイングユニットの土台となる白い枠を外す事が出来ます。

f:id:knob_create:20220730181926j:image

f:id:knob_create:20220730181920j:image

白い枠の裏面にはバーコードの様な反射板がありました。
f:id:knob_create:20220730181923j:image

反射板に向かうように配置されているのが反射型のセンサーになります。これの汚で読み取り不良を起こしていた様子です。アルコールで拭う事で改善しました。
f:id:knob_create:20220730181917j:image

あとは、同じ手順で組み立ててお終いです。

 

不具合の理由としては家の大型超音波加湿器の出すミストの残留成分の付着と思われます。センサーが隠れた場所についていたり、異物混入には気を遣っていますが、ものすごく小さいため対応出来ません。恐らくこのシステムが開発された当時は家一軒を丸ごと加湿する超音波加湿器の発想は無かったのでしょう。

 

分解しての感想ですが、かなりの部材がねじ止めで、かつ無理なく脱着できるので修理がやりやすいと感じました。座面ユニットは子供が吐いてしまっても丸洗も大丈夫かと思います。また、全体に丈夫なので壊れそうにもありません。次のご家庭でも、その先でも活躍してくれるでしょう。

 

最後に、分解修理は自己責任でお願いします。

 

 

All script of FUSION 360 postprocessor with backlash compensation for GRBL CNC lathe

Tip.
How to solve the backlash
This script divides the tool movement direction into four categories
 (1) 0 degree to 90 degree direction
 (2) 90 degrees to 180 degrees
 (3) 180 degrees to 270 degrees
 (4) 270 degrees to 360 degrees
When the movement direction of the tool changes, send the G54 to G57 commands to switch the coordinate system. This will cause the coordinate values to shift. If you send the G0 command to return to the original position, the tool tip position will not change, but the backlash will have been eliminated.

The values of G54 to G57 are stored in the controller such as GRBL. Please measure the amount of backlash on your machine and substitute the values.

----------------------------------------

description = "KNOB Turning";
vendor = "KNOB";
vendorUrl = "https://www.*****.com";
longDescription = "SIMPLE CONVERT CNC LATHE WITH BACKLASH CANCEL function";
legal = "Copyright (C) knob.create project";
certificationLevel = 2;
minimumRevision = 11111;

extension = "nc";
programNameIsInteger = false;
setCodePage("ascii");


capabilities = CAPABILITY_TURNING;
tolerance = spatial(0.002, MM);

minimumChordLength = spatial(0.25, MM);
minimumCircularRadius = spatial(0.01, MM);
maximumCircularRadius = spatial(1000, MM);
minimumCircularSweep = toRad(0.01);
maximumCircularSweep = toRad(180);
allowHelicalMoves = false;
allowedCircularPlanes = 1 << PLANE_ZX;


// user-defined properties
properties = {
writeMachine: false, // write machine
preloadTool: false, // preloads next tool on tool change if any
showSequenceNumbers: true, // show sequence numbers
sequenceNumberStart: 10, // first sequence number
sequenceNumberIncrement: 1, // increment for sequence numbers
optionalStop: true, // optional stop
separateWordsWithSpace: true, // specifies that the words should be separated with a white space
useRadius: false, // specifies that arcs should be output using the radius (R word) instead of the I, J, and K words.
maximumSpindleSpeed: 100 * 60, // specifies the maximum spindle speed
useParametricFeed: false, // specifies that feed should be output using Q values
showNotes: false, // specifies that operation notes should be output.
useCycles: true, // specifies that drilling cycles should be used.
g53HomePositionX: 0, // home position for X-axis
g53HomePositionZ: 0 // home position for Z-axis
};

// user-defined property definitions
propertyDefinitions = {
writeMachine: {title:"Write machine", description:"Output the machine settings in the header of the code.", group:0, type:"boolean"},
preloadTool: {title:"Preload tool", description:"Preloads the next tool at a tool change (if any).", type:"boolean"},
showSequenceNumbers: {title:"Use sequence numbers", description:"Use sequence numbers for each block of outputted code.", group:1, type:"boolean"},
sequenceNumberStart: {title:"Start sequence number", description:"The number at which to start the sequence numbers.", group:1, type:"integer"},
sequenceNumberIncrement: {title:"Sequence number increment", description:"The amount by which the sequence number is incremented by in each block.", group:1, type:"integer"},
optionalStop: {title:"Optional stop", description:"Outputs optional stop code during when necessary in the code.", type:"boolean"},
separateWordsWithSpace: {title:"Separate words with space", description:"Adds spaces between words if 'yes' is selected.", type:"boolean"},
useRadius: {title:"Radius arcs", description:"If yes is selected, arcs are outputted using radius values rather than IJK.", type:"boolean"},
maximumSpindleSpeed: {title:"Max spindle speed", description:"Defines the maximum spindle speed allowed by your machines.", type:"integer", range:[0, 999999999]},
useParametricFeed: {title:"Parametric feed", description:"Specifies the feed value that should be output using a Q value.", type:"boolean"},
showNotes: {title:"Show notes", description:"Writes operation notes as comments in the outputted code.", type:"boolean"},
useCycles: {title:"Use cycles", description:"Specifies if canned drilling cycles should be used.", type:"boolean"},
g53HomePositionX: {title:"G53 home position X", description:"G53 X-axis home position.", type:"number"},
g53HomePositionZ: {title:"G53 home position Z", description:"G53 Z-axis home position.", type:"number"}
};

 

 

 

var permittedCommentChars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,=_-";

var gFormat = createFormat({prefix:"G", decimals:0});
var mFormat = createFormat({prefix:"M", decimals:0});

var spatialFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true,trim:false,zeropad:true,width:8,forceSign:true});
var xFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true,trim:false,zeropad:true,width:8,forceSign:true});
var yFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true,trim:false,zeropad:true,width:8,forceSign:true});
var zFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true,trim:false,zeropad:true,width:8,forceSign:true,scale:1});
var rFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); // radius
var feedFormat = createFormat({decimals:(unit == MM ? 4 : 5), forceDecimal:true});
var pitchFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true});
var toolFormat = createFormat({decimals:0});
var rpmFormat = createFormat({decimals:0});
var secFormat = createFormat({decimals:3, forceDecimal:true}); // seconds - range 0.001-99999.999
var taperFormat = createFormat({decimals:1, scale:DEG});

var xOutput = createVariable({prefix:"X",force:true}, xFormat);//変化が無くても強制的に出す→可読性のため
var yOutput = createVariable({prefix:"Y",force:true}, yFormat);
var zOutput = createVariable({prefix:"Z",force:true}, zFormat);
var feedOutput = createVariable({prefix:"F",force:true}, feedFormat);
var pitchOutput = createVariable({prefix:"F", force:true}, pitchFormat);
var sOutput = createVariable({prefix:"S", force:true}, rpmFormat);

// circular output
var iOutput = createReferenceVariable({prefix:"I", force:true}, spatialFormat);
var jOutput = createReferenceVariable({prefix:"J", force:true}, spatialFormat);
var kOutput = createReferenceVariable({prefix:"K", force:true}, spatialFormat);

var g92IOutput = createVariable({prefix:"I"}, zFormat); // no scaling

var gMotionModal = createModal({force:true}, gFormat); // modal group 1 // G0-G3, ...
var gAbsIncModal = createModal({force:true}, gFormat); // modal group 3 // G90-91
var gUnitModal = createModal({force:true}, gFormat); // modal group 6 // G70-71
var gCycleModal = createModal({force:true}, gFormat); // modal group 9 // G81, ...
var gRetractModal = createModal({force:true}, gFormat); // modal group 10 // G98-99

// fixed settings
var gotSecondarySpindle = false;
var gotDoorControl = false;
var gotTailStock = true;
var gotBarFeeder = false;

var WARNING_WORK_OFFSET = 0;

var QCTP = 0;
var TURRET = 1;
var GANG = 2;

var FRONT = -1;
var REAR = 1;

// collected state
var sequenceNumber;
var currentWorkOffset;
var optionalSection = false;
var forceSpindleSpeed = false;
var toolingData;
var previousToolingData;

var pre_feed_direction = 3;

 

 

function getCode(code) {
switch(code) {
// case "PART_CATCHER_ON":
// return mFormat.format(SPECIFY YOUR CODE HERE);
// case "PART_CATCHER_OFF":
// return mFormat.format(SPECIFY YOUR CODE HERE);
case "TAILSTOCK_ON":
return mFormat.format(21);
case "TAILSTOCK_OFF":
return mFormat.format(22);
// case "ENGAGE_C_AXIS":
// machineState.cAxisIsEngaged = true;
// return cAxisEngageModal.format(UNSUPPORTED);
// case "DISENGAGE_C_AXIS":
// machineState.cAxisIsEngaged = false;
// return cAxisEngageModal.format(UNSUPPORTED);
// case "POLAR_INTERPOLATION_ON":
// return gPolarModal.format(UNSUPPORTED);
// case "POLAR_INTERPOLATION_OFF":
// return gPolarModal.format(UNSUPPORTED);
// case "STOP_LIVE_TOOL":
// machineState.liveToolIsActive = false;
// return mFormat.format(UNSUPPORTED);
// case "STOP_MAIN_SPINDLE":
// machineState.mainSpindleIsActive = false;
// return mFormat.format(UNSUPPORTED);
// case "STOP_SUB_SPINDLE":
// machineState.subSpindleIsActive = false;
// return mFormat.format(UNSUPPORTED);
// case "START_LIVE_TOOL_CW":
// machineState.liveToolIsActive = true;
// return mFormat.format(UNSUPPORTED);
// case "START_LIVE_TOOL_CCW":
// machineState.liveToolIsActive = true;
// return mFormat.format(UNSUPPORTED);
case "START_MAIN_SPINDLE_CW":
// machineState.mainSpindleIsActive = true;
return mFormat.format(3);
case "START_MAIN_SPINDLE_CCW":
// machineState.mainSpindleIsActive = true;
return mFormat.format(4);
// case "START_SUB_SPINDLE_CW":
// machineState.subSpindleIsActive = true;
// return mFormat.format(UNSUPPORTED);
// case "START_SUB_SPINDLE_CCW":
// machineState.subSpindleIsActive = true;
// return mFormat.format(UNSUPPORTED);
// case "MAIN_SPINDLE_BRAKE_ON":
// machineState.mainSpindleBrakeIsActive = true;
// return cAxisBrakeModal.format(UNSUPPORTED);
// case "MAIN_SPINDLE_BRAKE_OFF":
// machineState.mainSpindleBrakeIsActive = false;
// return cAxisBrakeModal.format(UNSUPPORTED);
// case "SUB_SPINDLE_BRAKE_ON":
// machineState.subSpindleBrakeIsActive = true;
// return cAxisBrakeModal.format(UNSUPPORTED);
// case "SUB_SPINDLE_BRAKE_OFF":
// machineState.subSpindleBrakeIsActive = false;
// return cAxisBrakeModal.format(UNSUPPORTED);
// case "FEED_MODE_UNIT_REV":
// return gFeedModeModal.format(UNSUPPORTED);
// case "FEED_MODE_UNIT_MIN":
// return gFeedModeModal.format(UNSUPPORTED);
case "CONSTANT_SURFACE_SPEED_ON":
return gSpindleModeModal.format(96);
case "CONSTANT_SURFACE_SPEED_OFF":
return gSpindleModeModal.format(97);
// case "MAINSPINDLE_AIR_BLAST_ON":
// return mFormat.format(UNSUPPORTED);
// case "MAINSPINDLE_AIR_BLAST_OFF":
// return mFormat.format(UNSUPPORTED);
// case "SUBSPINDLE_AIR_BLAST_ON":
// return mFormat.format(UNSUPPORTED);
// case "SUBSPINDLE_AIR_BLAST_OFF":
// return mFormat.format(UNSUPPORTED);
// case "CLAMP_PRIMARY_CHUCK":
// return mFormat.format(UNSUPPORTED);
// case "UNCLAMP_PRIMARY_CHUCK":
// return mFormat.format(UNSUPPORTED);
// case "CLAMP_SECONDARY_CHUCK":
// return mFormat.format(UNSUPPORTED);
// case "UNCLAMP_SECONDARY_CHUCK":
// return mFormat.format(UNSUPPORTED);
// case "SPINDLE_SYNCHRONIZATION_ON":
// machineState.spindleSynchronizationIsActive = true;
// return gSynchronizedSpindleModal.format(UNSUPPORTED);
// case "SPINDLE_SYNCHRONIZATION_OFF":
// machineState.spindleSynchronizationIsActive = false;
// return gSynchronizedSpindleModal.format(UNSUPPORTED);
// case "START_CHIP_TRANSPORT":
// return mFormat.format(UNSUPPORTED);
// case "STOP_CHIP_TRANSPORT":
// return mFormat.format(UNSUPPORTED);
// case "OPEN_DOOR":
// return mFormat.format(UNSUPPORTED);
// case "CLOSE_DOOR":
// return mFormat.format(UNSUPPORTED);
// case "COOLANT_FLOOD_ON":
// return mFormat.format(UNSUPPORTED);
// case "COOLANT_FLOOD_OFF":
// return mFormat.format(UNSUPPORTED);
// case "COOLANT_AIR_ON":
// return mFormat.format(UNSUPPORTED);
// case "COOLANT_AIR_OFF":
// return mFormat.format(UNSUPPORTED);
// case "COOLANT_THROUGH_TOOL_ON":
// return mFormat.format(UNSUPPORTED);
// case "COOLANT_THROUGH_TOOL_OFF":
// return mFormat.format(UNSUPPORTED);
// case "COOLANT_OFF":
// return mFormat.format(UNSUPPORTED);
default:
error(localize("Command " + code + " is not defined."));
return 0;
}
}

/**
Writes the specified block.
*/
function writeBlock() {
if (properties.showSequenceNumbers) {
if (optionalSection) {
var text = formatWords(arguments);
if (text) {
// writeWords("/", "N" + sequenceNumber, text);
writeWords("/", "" + "", text);
}
} else {
//writeWords2("N" + sequenceNumber, arguments);
writeWords2("" + "", arguments);

}
sequenceNumber += properties.sequenceNumberIncrement;
} else {
if (optionalSection) {
writeWords2("/", arguments);
} else {
writeWords(arguments);
}
}
}

/**
Writes the specified optional block.
*/
function writeOptionalBlock() {
if (properties.showSequenceNumbers) {
var words = formatWords(arguments);
if (words) {
writeWords("/", "N" + sequenceNumber, words);
sequenceNumber += properties.sequenceNumberIncrement;
}
} else {
writeWords2("/", arguments);
}
}

function formatComment(text) {
return "; " + String(text).replace(/[()]/g, "");
}

/**
Output a comment.
*/
function writeComment(text) {
writeln(formatComment(text));
}

function backlash_comp(feed_direction,sx,sy,sz){

if(feed_direction != pre_feed_direction){
switch(feed_direction){
case 1:
writeln("G55");

break;

case 2:
writeln("G56");
break;

case 3:
writeln("G57");
break;

case 4:
writeln("G54");
break;
}
writeBlock(gMotionModal.format(0),xOutput.format(sx),yOutput.format(sy),zOutput.format(sz)); //バックラッシュ解消動作
pre_feed_direction = feed_direction;//今回の向きを記憶し、次回に備える。

}
}

 

function onOpen() {

sequenceNumber = properties.sequenceNumberStart;
writeln("G18");
writeln("G90");

}

function onComment(message) {
writeln("-------------------------------onComment");
writeln(message);
writeln("**********");
writeln("");
}

/** Force output of X, Y, and Z. */
function forceXYZ() {
writeln("-------------------------------forceXYZ");
writeln("**********");
writeln("");
}

/** Force output of X, Y, Z, and F on next output. */
function forceAny() {
writeln("-------------------------------forceAny");
writeln("**********");
writeln("");
}

function getSpindle() {
writeln("-------------------------------getSpindle");
writeln("**********");
writeln("");

}

function ToolingData(_tool) {
writeln("-------------------------------ToolingData");
writeln(_tool);
writeln("**********");
writeln("");

}

function onSection() {
/*
writeln("-------------------------------onSection");
writeln("**********");
writeln("");
*/

}

function onSpindleSpeed(spindleSpeed) {
writeln("-------------------------------onSpindleSpeed");
writeln(spindleSpeed);
writeln("**********");
writeln("");

}

function onDwell(seconds) {
writeln("-------------------------------onDwell");
writeln(second);
writeln("**********");
writeln("");


}

var pendingRadiusCompensation = -1;

function onRadiusCompensation() {
writeln("-------------------------------onRadiusCompensation");
writeln("**********");
writeln("");

}

var resetFeed = false;


//-------------------------------G0位置決め(早送り)
function onRapid(_x, _y, _z) {

var Fdirection;
var start00 = getCurrentPosition();//start.x/y/zにスタート位置が保存される

if(_z-start00.z<=0 && _x-start00.x<=0) Fdirection = 3;
if(_z-start00.z<=0 && _x-start00.x>0) Fdirection = 2;
if(_z-start00.z>0 && _x-start00.x<=0) Fdirection = 4;
if(_z-start00.z>0 && _x-start00.x>0) Fdirection = 1;

backlash_comp(Fdirection,start00.x,start00.y,start00.z);

writeBlock(gMotionModal.format(0),xOutput.format(_x),yOutput.format(_y),zOutput.format(_z));
}

//-------------------------------G01直線補完
function onLinear(_x, _y, _z, feed) {

//ここの処理で何故かバックラッシュ補償の行が先に実行されている様子。順序を整えないといけない。

var Fdirection;

var start01 = getCurrentPosition();//start.x/y/zにスタート位置が保存される


if(_z-start01.z<=0 && _x-start01.x<=0) Fdirection = 3;
if(_z-start01.z<=0 && _x-start01.x>0) Fdirection = 2;
if(_z-start01.z>0 && _x-start01.x<=0) Fdirection = 4;
if(_z-start01.z>0 && _x-start01.x>0) Fdirection = 1;

if(_z-start01.z>0) feed = 300;

backlash_comp(Fdirection,start01.x,start01.y,start01.z);


writeBlock(gMotionModal.format(1),xOutput.format(_x),yOutput.format(_y),zOutput.format(_z),feedOutput.format(feed));


}


//-------------------------------G02/03円弧補完
function onCircular(clockwise, cx, cy, cz, x, y, z, feed) {

//軸通過ごとに分割するプログラムに変更し、バックラッシュ補完の前段階までを行う。

 

var start = getCurrentPosition();//start.x/y/zにスタート位置が保存される

var direction_circle;

if(clockwise == true){
direction_circle = 2;
}else{
direction_circle = 3;
}
//時計回りと反時計回りのG2 G3設定


var ctr_pt = {xx:cx,yy:cy,zz:cz};
var str_pt = {xx:start.x,yy:start.y,zz:start.z};
var end_pt = {xx:x,yy:y,zz:z};
//各座標のオブジェクトの生成

var pass_rad;
pass_rad = Math.sqrt(
(str_pt.xx-ctr_pt.xx)*(str_pt.xx-ctr_pt.xx)+
(str_pt.yy-ctr_pt.yy)*(str_pt.yy-ctr_pt.yy)+
(str_pt.zz-ctr_pt.zz)*(str_pt.zz-ctr_pt.zz)
);
//回転半径の算出


var quadrant_start;
var quadrant_end;

if (str_pt.zz-ctr_pt.zz>=0 &&str_pt.xx-ctr_pt.xx>=0){quadrant_start = 1}
if (str_pt.zz-ctr_pt.zz< 0 &&str_pt.xx-ctr_pt.xx>=0){quadrant_start = 2}
if (str_pt.zz-ctr_pt.zz< 0 &&str_pt.xx-ctr_pt.xx< 0){quadrant_start = 3}
if (str_pt.zz-ctr_pt.zz>=0 &&str_pt.xx-ctr_pt.xx< 0){quadrant_start = 4}

if (end_pt.zz-ctr_pt.zz>=0 &&end_pt.xx-ctr_pt.xx>=0){quadrant_end = 1}
if (end_pt.zz-ctr_pt.zz< 0 &&end_pt.xx-ctr_pt.xx>=0){quadrant_end = 2}
if (end_pt.zz-ctr_pt.zz< 0 &&end_pt.xx-ctr_pt.xx< 0){quadrant_end = 3}
if (end_pt.zz-ctr_pt.zz>=0 &&end_pt.xx-ctr_pt.xx< 0){quadrant_end = 4}
//開始点と終了点の象限の管理

 

//開始と終了点の象限が同じ場合、小回りなのか大回りなのかを判断する。
var rot_type;
rot_type = (str_pt.xx-ctr_pt.xx) * (end_pt.zz-ctr_pt.zz) -(str_pt.zz-ctr_pt.zz) * (end_pt.xx-ctr_pt.xx);

var process_position_array = new Array(0,0,0,0,0); //値の初期化
var process_type_array = new Array("no","no","no","no","no"); //値の初期化

 


//パターン1:開始と終了の象限が同じ場合

//clockwiseがfalseかつrot_typeが負の場合、小回り
//clockwiseがtrue かつrot_typeが正の場合、小回り

//clockwiseがtrue かつrot_typeが負の場合、大回り
//clockwiseがfalseかつrot_typeが正の場合、大回り


if(quadrant_start == quadrant_end &&clockwise == false && rot_type <0){
process_position_array = [quadrant_start,0,0,0,0];
process_type_array = ["st_ed","no","no","no","no"];
}

if(quadrant_start == quadrant_end &&clockwise == true && rot_type >0){
process_position_array = [quadrant_start,0,0,0,0];
process_type_array = ["st_ed","no","no","no","no"];
}

if(quadrant_start == quadrant_end &&clockwise == true && rot_type <0){
process_position_array = [(quadrant_start-1+4-0)%4+1,
(quadrant_start-1+4-1)%4+1,
(quadrant_start-1+4-2)%4+1,
(quadrant_start-1+4-3)%4+1,
(quadrant_start-1+4-4)%4+1];
process_type_array = ["start","mid","mid","mid","end"];
}

if(quadrant_start == quadrant_end &&clockwise == false && rot_type >0){
process_position_array = [(quadrant_start-1+4+0)%4+1,
(quadrant_start-1+4+1)%4+1,
(quadrant_start-1+4+2)%4+1,
(quadrant_start-1+4+3)%4+1,
(quadrant_start-1+4+4)%4+1];
process_type_array = ["start","mid","mid","mid","end"];
}

//パターン2:開始と終了の象限が異なる場合

//時計回りの場合
if(quadrant_start != quadrant_end && clockwise == true){

var ci;
for ( ci = 0; ci < 5; ci++ ) {
process_position_array[ci] = (quadrant_start-1+4-ci)%4+1;
if(process_position_array[ci] == quadrant_start && process_position_array[ci] != quadrant_end){
process_type_array[ci]="start"
}

if(process_position_array[ci] != quadrant_start && process_position_array[ci] != quadrant_end)
{
process_type_array[ci]="mid"
}

if(process_position_array[ci] != quadrant_start && process_position_array[ci] == quadrant_end){
process_type_array[ci]="end"
break;
}
}

}


//反時計回りの場合
if(quadrant_start != quadrant_end && clockwise == false){

var ci;
for ( ci = 0; ci < 5; ci++ ) {
process_position_array[ci] = (quadrant_start-1+4+ci)%4+1;
if(process_position_array[ci] == quadrant_start && process_position_array[ci] != quadrant_end){
process_type_array[ci]="start"
}

if(process_position_array[ci] != quadrant_start && process_position_array[ci] != quadrant_end)
{
process_type_array[ci]="mid"
}

if(process_position_array[ci] != quadrant_start && process_position_array[ci] == quadrant_end){
process_type_array[ci]="end"
break;
}
}
}

//ここまでは処理条件の配列の設定のみ

//writeln("(------check background data---------------)");
//writeln(";start point:"+str_pt.xx +","+str_pt.yy +","+str_pt.zz);
//writeln(";ctr point:"+ctr_pt.xx +","+ctr_pt.yy +","+ctr_pt.zz);
//writeln(";end point:"+end_pt.xx +","+end_pt.yy +","+end_pt.zz);
//writeln(";start area:"+quadrant_start);
//writeln(";end area:"+quadrant_end);
//writeln(";min route type:"+rot_type);
//writeln(";rot direction:"+clockwise);
//writeln(process_position_array);
//writeln(process_type_array);


//G-CODEの場合別出力
var ki;
for ( ki = 0; ki < 5; ki++ ) {

 


if(process_type_array[ki] =="st_ed"){

if (quadrant_start == 1 && clockwise == true) backlash_comp(4,str_pt.xx,str_pt.yy,str_pt.zz);
if (quadrant_start == 2 && clockwise == true) backlash_comp(1,str_pt.xx,str_pt.yy,str_pt.zz);
if (quadrant_start == 3 && clockwise == true) backlash_comp(2,str_pt.xx,str_pt.yy,str_pt.zz);
if (quadrant_start == 4 && clockwise == true) backlash_comp(3,str_pt.xx,str_pt.yy,str_pt.zz);

if (quadrant_start == 1 && clockwise == false) backlash_comp(2,str_pt.xx,str_pt.yy,str_pt.zz);
if (quadrant_start == 2 && clockwise == false) backlash_comp(3,str_pt.xx,str_pt.yy,str_pt.zz);
if (quadrant_start == 3 && clockwise == false) backlash_comp(4,str_pt.xx,str_pt.yy,str_pt.zz);
if (quadrant_start == 4 && clockwise == false) backlash_comp(1,str_pt.xx,str_pt.yy,str_pt.zz);


writeBlock(gMotionModal.format(direction_circle),
xOutput.format(end_pt.xx),
yOutput.format(end_pt.yy),
zOutput.format(end_pt.zz),
iOutput.format(ctr_pt.xx-str_pt.xx,0),
jOutput.format(ctr_pt.yy-str_pt.yy,0),
kOutput.format(ctr_pt.zz-str_pt.zz,0),
feedOutput.format(feed));
// writeln("check_write");
}//↑同一象限内の移動

if(process_type_array[ki] =="start"){

//writeln("for start");

if (quadrant_start == 1 && clockwise == true) backlash_comp(4,str_pt.xx,str_pt.yy,str_pt.zz);
if (quadrant_start == 2 && clockwise == true) backlash_comp(1,str_pt.xx,str_pt.yy,str_pt.zz);
if (quadrant_start == 3 && clockwise == true) backlash_comp(2,str_pt.xx,str_pt.yy,str_pt.zz);
if (quadrant_start == 4 && clockwise == true) backlash_comp(3,str_pt.xx,str_pt.yy,str_pt.zz);

if (quadrant_start == 1 && clockwise == false) backlash_comp(2,str_pt.xx,str_pt.yy,str_pt.zz);
if (quadrant_start == 2 && clockwise == false) backlash_comp(3,str_pt.xx,str_pt.yy,str_pt.zz);
if (quadrant_start == 3 && clockwise == false) backlash_comp(4,str_pt.xx,str_pt.yy,str_pt.zz);
if (quadrant_start == 4 && clockwise == false) backlash_comp(1,str_pt.xx,str_pt.yy,str_pt.zz);

if(clockwise == true && quadrant_start ==1 && Math.abs(ctr_pt.xx-str_pt.xx)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(ctr_pt.xx),
yOutput.format(ctr_pt.yy),
zOutput.format(ctr_pt.zz+pass_rad),
iOutput.format(ctr_pt.xx-str_pt.xx,0),
jOutput.format(ctr_pt.yy-str_pt.yy,0),
kOutput.format(ctr_pt.zz-str_pt.zz,0),
feedOutput.format(feed));

str_pt.xx = ctr_pt.xx;
str_pt.yy = ctr_pt.yy;
str_pt.zz = ctr_pt.zz+pass_rad;
}
if(clockwise == true && quadrant_start ==2 && Math.abs(ctr_pt.zz-str_pt.zz)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(ctr_pt.xx+pass_rad),
yOutput.format(ctr_pt.yy),
zOutput.format(ctr_pt.zz),
iOutput.format(ctr_pt.xx-str_pt.xx,0),
jOutput.format(ctr_pt.yy-str_pt.yy,0),
kOutput.format(ctr_pt.zz-str_pt.zz,0),
feedOutput.format(feed));
str_pt.xx= (ctr_pt.xx+pass_rad);
str_pt.yy= (ctr_pt.yy);
str_pt.zz= (ctr_pt.zz);
}
if(clockwise == true && quadrant_start ==3 && Math.abs(ctr_pt.xx-str_pt.xx)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(ctr_pt.xx),
yOutput.format(ctr_pt.yy),
zOutput.format(ctr_pt.zz-pass_rad),
iOutput.format(ctr_pt.xx-str_pt.xx,0),
jOutput.format(ctr_pt.yy-str_pt.yy,0),
kOutput.format(ctr_pt.zz-str_pt.zz,0),
feedOutput.format(feed));

str_pt.xx= (ctr_pt.xx);
str_pt.yy= (ctr_pt.yy);
str_pt.zz= (ctr_pt.zz-pass_rad);
}
if(clockwise == true && quadrant_start ==4 && Math.abs(ctr_pt.zz-str_pt.zz)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(ctr_pt.xx-pass_rad),
yOutput.format(ctr_pt.yy),
zOutput.format(ctr_pt.zz),
iOutput.format(ctr_pt.xx-str_pt.xx,0),
jOutput.format(ctr_pt.yy-str_pt.yy,0),
kOutput.format(ctr_pt.zz-str_pt.zz,0),
feedOutput.format(feed));

str_pt.xx= (ctr_pt.xx-pass_rad);
str_pt.yy= (ctr_pt.yy);
str_pt.zz= (ctr_pt.zz);
}

if(clockwise == false && quadrant_start ==1 && Math.abs(ctr_pt.zz-str_pt.zz)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(ctr_pt.xx+pass_rad),
yOutput.format(ctr_pt.yy),
zOutput.format(ctr_pt.zz),
iOutput.format(ctr_pt.xx-str_pt.xx,0),
jOutput.format(ctr_pt.yy-str_pt.yy,0),
kOutput.format(ctr_pt.zz-str_pt.zz,0),
feedOutput.format(feed));

str_pt.xx=ctr_pt.xx+pass_rad;
str_pt.yy=ctr_pt.yy;
str_pt.zz=ctr_pt.zz;
}
if(clockwise == false && quadrant_start ==2 && Math.abs(ctr_pt.xx-str_pt.xx)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(ctr_pt.xx),
yOutput.format(ctr_pt.yy),
zOutput.format(ctr_pt.zz-pass_rad),
iOutput.format(ctr_pt.xx-str_pt.xx,0),
jOutput.format(ctr_pt.yy-str_pt.yy,0),
kOutput.format(ctr_pt.zz-str_pt.zz,0),
feedOutput.format(feed));

str_pt.xx=ctr_pt.xx;
str_pt.yy=ctr_pt.yy;
str_pt.zz=ctr_pt.zz-pass_rad;

}
if(clockwise == false && quadrant_start ==3 && Math.abs(ctr_pt.zz-str_pt.zz)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(ctr_pt.xx-pass_rad),
yOutput.format(ctr_pt.yy),
zOutput.format(ctr_pt.zz),
iOutput.format(ctr_pt.xx-str_pt.xx,0),
jOutput.format(ctr_pt.yy-str_pt.yy,0),
kOutput.format(ctr_pt.zz-str_pt.zz,0),
feedOutput.format(feed));

str_pt.xx=(ctr_pt.xx-pass_rad);
str_pt.yy= (ctr_pt.yy);
str_pt.zz= (ctr_pt.zz);
}
if(clockwise == false && quadrant_start ==4 && Math.abs(ctr_pt.xx-str_pt.xx)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(ctr_pt.xx),
yOutput.format(ctr_pt.yy),
zOutput.format(ctr_pt.zz+pass_rad),
iOutput.format(ctr_pt.xx-str_pt.xx,0),
jOutput.format(ctr_pt.yy-str_pt.yy,0),
kOutput.format(ctr_pt.zz-str_pt.zz,0),
feedOutput.format(feed));

str_pt.xx= (ctr_pt.xx);
str_pt.yy= (ctr_pt.yy);
str_pt.zz= (ctr_pt.zz+pass_rad);
}

}//↑異なる象限間の移動で最初のセクション

if(process_type_array[ki] =="mid"){

writeln("mid");
}//↑異なる象限間の移動で途中のセクション

if(process_type_array[ki] =="end"){

//writeln("for end");


if (quadrant_end == 1 && clockwise == true) backlash_comp(4,ctr_pt.xx+pass_rad,0,ctr_pt.zz);
if (quadrant_end == 2 && clockwise == true) backlash_comp(1,ctr_pt.xx,0,ctr_pt.zz-pass_rad);
if (quadrant_end == 3 && clockwise == true) backlash_comp(2,ctr_pt.xx-pass_rad,0,ctr_pt.zz);
if (quadrant_end == 4 && clockwise == true) backlash_comp(3,ctr_pt.xx,0,ctr_pt.zz+pass_rad);

if (quadrant_end == 1 && clockwise == false) backlash_comp(2,ctr_pt.xx,0,ctr_pt.zz+pass_rad);
if (quadrant_end == 2 && clockwise == false) backlash_comp(3,ctr_pt.xx+pass_rad,0,ctr_pt.zz);
if (quadrant_end == 3 && clockwise == false) backlash_comp(4,ctr_pt.xx,0,ctr_pt.zz-pass_rad);
if (quadrant_end == 4 && clockwise == false) backlash_comp(1,ctr_pt.xx-pass_rad,0,ctr_pt.zz);


if(clockwise == true && quadrant_end ==1 &&Math.abs(end_pt.zz-ctr_pt.zz)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(end_pt.xx),
yOutput.format(end_pt.yy),
zOutput.format(end_pt.zz),
iOutput.format(-pass_rad,0),
jOutput.format(0,0),
kOutput.format(0,0),
feedOutput.format(feed));
}
if(clockwise == true && quadrant_end ==2 &&Math.abs(end_pt.xx-ctr_pt.xx)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(end_pt.xx),
yOutput.format(end_pt.yy),
zOutput.format(end_pt.zz),
iOutput.format(0,0),
jOutput.format(0,0),
kOutput.format(pass_rad,0),
feedOutput.format(feed));
}
if(clockwise == true && quadrant_end ==3 &&Math.abs(end_pt.zz-ctr_pt.zz)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(end_pt.xx),
yOutput.format(end_pt.yy),
zOutput.format(end_pt.zz),
iOutput.format(pass_rad,0),
jOutput.format(0,0),
kOutput.format(0,0),
feedOutput.format(feed));

}
if(clockwise == true && quadrant_end ==4 &&Math.abs(end_pt.xx-ctr_pt.xx)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(end_pt.xx),
yOutput.format(end_pt.yy),
zOutput.format(end_pt.zz),
iOutput.format(0,0),
jOutput.format(0,0),
kOutput.format(-pass_rad,0),
feedOutput.format(feed));

}

if(clockwise == false && quadrant_end ==1 &&Math.abs(end_pt.xx-ctr_pt.xx)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(end_pt.xx),
yOutput.format(end_pt.yy),
zOutput.format(end_pt.zz),
iOutput.format(0,0),
jOutput.format(0,0),
kOutput.format(-pass_rad,0),
feedOutput.format(feed));

}
if(clockwise == false && quadrant_end ==2 &&Math.abs(end_pt.zz-ctr_pt.zz)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(end_pt.xx),
yOutput.format(end_pt.yy),
zOutput.format(end_pt.zz),
iOutput.format(-pass_rad,0),
jOutput.format(0,0),
kOutput.format(0,0),
feedOutput.format(feed));


}
if(clockwise == false && quadrant_end ==3 &&Math.abs(end_pt.xx-ctr_pt.xx)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(end_pt.xx),
yOutput.format(end_pt.yy),
zOutput.format(end_pt.zz),
iOutput.format(0,0),
jOutput.format(0,0),
kOutput.format(pass_rad,0),
feedOutput.format(feed));


}
if(clockwise == false && quadrant_end ==4 &&Math.abs(end_pt.zz-ctr_pt.zz)>0.001){
writeBlock(gMotionModal.format(direction_circle),
xOutput.format(end_pt.xx),
yOutput.format(end_pt.yy),
zOutput.format(end_pt.zz),
iOutput.format(pass_rad,0),
jOutput.format(0,0),
kOutput.format(0,0),
feedOutput.format(feed));


}

 

}//↑異なる象限間の移動で最後のセクション

if(process_type_array[ki] =="no"){
}//作業完了後の処理なので何もしない。

}


}

function onCycle() {
writeln(";-------------------------------ONCycle");
writeln(";**********");
writeln("");

}

function getCommonCycle(x, y, z, r) {
writeln("-------------------------------getCommonCycle");
writeln(x);
writeln(y);
writeln(z);
writeln(r);
writeln("**********");
writeln("");

}

function onCyclePoint(x, y, z) {
writeln("-------------------------------oncyclepoint");
writeln(x);
writeln(y);
writeln(z);
writeln("**********");
writeln("");

}

function onCycleEnd() {
writeln("-------------------------------oncycleend");
writeln("**********");
writeln("");

}

var currentCoolantMode = COOLANT_OFF;

function setCoolant(coolant) {
writeln("-------------------------------setcoolant");
writeln(coolant);
writeln("**********");
writeln("");

}

function onCommand(command) {
writeln("-------------------------------oncommand");
writeln(command);
writeln("**********");
writeln("");
}

function engagePartCatcher(engage) {
writeln("-------------------------------engagePartCatcher");
writeln(engage);
writeln("**********");
writeln("");

}

function onSectionEnd() {
/*
writeln("-------------------------------ONSECTIONEND");
writeln("**********");
writeln("");
*/

}

function onClose() {
/*
writeln("-------------------------------ONCLOSE");
writeln("**********");
writeln("");
*/
}

picorettaのwindowsアップグレード 失敗編

以前紹介したステックPCのPicorettaですが、最近になってCNC旋盤とレーザー加工機の制御パソコンとしての使い道ができました。ただ少々問題があり、搭載しているWindowsが8のBingで8を飛ばしてきた私にとってはUIがストレスでしかありません。

 

そこで、もしかして。。と思いWindowsのアップグレードを試みる事にしました。

やりかたは至って普通でマイクロソフトのサイトにあるツールを用いてオンラインで更新します。
f:id:knob_create:20191012143504j:image

 ツールをダウンロードして、実行をすると、下の画面で少し待たされます。

f:id:knob_create:20191012143553j:image

 最初にライセンスですね、同意しておきましょう。

f:id:knob_create:20191012143917j:image

 また準備中です。

f:id:knob_create:20191012143935j:image

次に作業を選びます。このままアップグレードなので、上のボタンでOKです。

f:id:knob_create:20191012144302j:image

 

ダウンロードが始まりました。基本的には当分放置です。

f:id:knob_create:20191012144455j:image

 

またライセンス。これはWindowsそのものへの同意ですね

f:id:knob_create:20191012150136j:image

 

この画面の前に一瞬引き継ぐ項目と出たが、そのまま消えました。

環境によっては選択肢が提示されるのかもしれませんね。

自動でインストールが開始されます。

f:id:knob_create:20191012150357j:image

 

なぜか更新プログラムのチェックが46%で止まりました。特に何か選択肢のWindowが出てはいないし、タスクマネージャーではCPUが動いているので何かしているのかもしれません。低SPECなので時間がかかると思えばいいのかな。こういうときは待つに限ります。

f:id:knob_create:20191012152335j:image

 

 4時間ほど放置しましたが、何も変わりませんでした。

調べた所この46%でストップする事象は他でも報告されており、

ひとまずインストールメディアを作成するルートで回避できそうとの事なので、そっちも試してみようと思います。

 

FUSION 360 postprocessor with backlash compensation for GRBL CNC lathe

 


FUSION 360 postprocessor with backlash compensation for GRBL CNC lathe

 

you can get all script from below link

knob-create.hatenablog.jp

 

Fusin360 is a good 3D CAD for parsonal use.

Not only CAD functions but also CAM functions are enriched.

f:id:knob_create:20190424221929p:plain

 

Today I want to focus the function for CNC lathe.

Fusion360's CAM make tool path based on designed data.

 

f:id:knob_create:20190424231816p:plain

However, this tool pathe and Fusion 360 cannot control GRBL Board directory.

you need G-CODE data to control  as blow.

 

f:id:knob_create:20190424231942p:plain

 

So, we need a function called postprocessor to translate from toolpath to G-CODE.

Of course Fusion360 have this function.you can use it from G1/G2 icon.

but attached postprocessor does not work well.there is two reasons.

 

 

1)a value of X axis is written by diameter,but GRBL understand it as radius.

2)a lathe which is not use ball screw for feed , need backlash compensation.

 

f:id:knob_create:20190424232240p:plain

f:id:knob_create:20190424232216p:plain

 

So,I made a postprocessor which use x value in radius and have backlash compensation.

the result was parfect.please show youtube video or picture below

f:id:knob_create:20190424235243j:plain

f:id:knob_create:20190424235337j:plain

 f:id:knob_create:20190424235341j:plain



 

フライス盤 Z軸のボールネジ化

フライス盤のZ軸にボールネジの送り機構を追加しました。

 

元がラックランドピニオンで、ガタの大きくまともに加工できません。

 

現在ラックの入っている位置にスロット穴を設け、コラムの中にネジを仕込みたいのですが、それには別のフライス盤が必要なので出来ません。なので外掛けです。

剛性をもって荷重伝達できるようにナットは2個掛けにしています。そのほかにもヘッド側の締め付けも4点とし、つなぐプレートはSS400の10mm厚にしました。

f:id:knob_create:20190203145029j:plain

この仕様でバックラッシュ0と言いたいところですが、主軸付近で0.06mm程度残っています。ボールネジ付近は回転にリニアに動いているので、カミソリの当たりが出れば改善されるかもしれません。

 

必要なトルクですが、前回の投稿では0.1Nm程度かと想定していましたが、簡易に測定したところ0.7Nm程度でした。ざっくり計算すると1kN程度の推力になっています。その差はカミソリの部分の摩擦と思います。

 

そこで、ステッピングモータは余裕をもって23HS45-4204Sを選定しました。

詳細のスペックはここにあります。

www.omc-stepperonline.com

 

配線はこのようになっています。

f:id:knob_create:20190203150912p:plain

回転数とトルクの関係はこのようになっています。

ハーフステップで200Ncm出せているので、1/4程度のマイクロステップなら使えそうです。その場合800step/rotですから、0.005mm程度の分解能になります。

f:id:knob_create:20190203150557p:plain

 ドライバーはICにTB6600を使っているこちらにしました

f:id:knob_create:20190203223345j:image

 

CNC制御は専用のコントローラを購入しました。

スタンドアロンで操作することが可能です。

f:id:knob_create:20190203223547j:image

 

 

f:id:knob_create:20190223114353j:image