Hello!
I’m trying to modify the basic kirimoto api example (Kiri:Moto Javascript Engine API) to suit a CNC application but can’t seem to be able to find the available parameters for device and set process. I have changed the mode to CAM but I’m not sure what the correct syntax or available settings are available for the operations and the machine nor how to set them. Any help would be really appreciated.
Thank you
Specifically we are doing:
kiriEngine
.setListener((message) => {
console.log("Kiri:Moto Message:", message);
})
.load(stlUrl) // Use the temporary file URL here // or stlUrl
.then((eng) => {
console.log("STL file loaded");
console.log(eng);
return eng.setProcess({
sliceShells: 1,
sliceFillSparse: 0.1,
sliceTopLayers: 1,
sliceBottomLayers: 1,
});
})
Which works great to generate gcode for 3D printing, but if we wanted to do a CNC operation instead how would we set that up?
Hey there, Great question. Here’s a quick example I spun up. I’d keep in mind that only the outline , contour, rough, contour, level, and gcode operations are global, and can be used easily in the engine.
kiri.newEngine()
.setListener(display_message)
.load("/obj/cube.stl")
.then(eng => eng.setMode("CAM"))
.then(eng => eng.setStock({
"x": 110.00001525878906,
"y": 60,
"z": 60,
"center": {
"x": 0,
"y": 0,
"z": 12.5
}
}))
.then(eng=> eng.setTools([
{
"id": 1722394350168,
"number": 11,
"name": "0.3 mm",
"type": "endmill",
"shaft_diam": 0.3,
"shaft_len": 5,
"flute_diam": 0.3,
"flute_len": 5,
"taper_tip": 0,
"metric": true,
"order": 0
}
]))
.then(eng => eng.setProcess({
ops:[
{
"type":"outline",
"tool":1722394350168,
"spindle":15000,
"step":0.4,
"steps":1,"down":1,
"rate":2500,
"plunge":150,
"dogbones":false,
"omitvoid":false,
"omitthru":false,
"outside":false,
"inside":false,
"wide":false,
"top":false,
},
]
}))
.then(eng => eng.setDevice({
"mode": "CAM",
"internal": 0,
"bedHeight": 2.5,
"bedWidth": 678.18,
"bedDepth": 1524,
"maxHeight": 150,
"originCenter": false,
"spindleMax": 24000,
"gcodePre": [
"G20 ; set units to inches (required)",
"G90 ; absolute position mode (required)"
],
"gcodePost": [
"M05 ; spindle off",
"M30 ; program end"
],
"gcodeDwell": [
"G4 P{time} ; dwell for {time}ms"
],
"gcodeSpindle": [
"M3 S{speed} ; spindle on at {spindle} rpm"
],
"gcodeChange": [
"M05 ; spindle off",
"M6 T{tool} ; change tool to '{tool_name}'",
"G37; get tool offset with ETS"
],
"gcodeFExt": "nc",
"gcodeSpace": true,
"gcodeStrip": false,
"deviceName": "Tormach.24R",
"imageURL": "",
"useLaser": false
}))
.then(eng => eng.slice())
.then(eng => eng.prepare())
.then(eng => eng.export())
.then(display_gcode);
It seems that the setTools and setStock methods are missing from the engine page. I’ve made a github issue to add these to the page along with better documentation.
In the meantime, you can see the options for tools, stock, and process by making your desired CAM operation in kiri:moto and then in the developer console typing kiri.api.settings.get(). Doing so will return an object with all of the configurable options.
Hope this helps.
Scratch that. Seems that the code I provided doesn’t actually generate anything. I’m going to dig a bit deeper. Sorry I jumped the gun on this one.
Well that code looks like a perfect answer so thank you for that! Broadly speaking I really really appreciate the work that y’all are doing. It’s spectacular.
Thanks! I’m proud to be a part of the KM community.
It turns out that the code I provided is mostly fine, but there’s a bug in the KM code that keeps the code from exporting. I’m working on a PR to fix it, and it will likely be out in the next release.
You rock! Thank you!
I’m a little late to the conversation, but this is great news! Thanks for the work you do!
It looks to me like the PR is merged? If we update our version of Kirimoto can we use CAM mode or do we need to wait for a release?
You’ll need to wait for a release to see it on the Kiri:Moto Javascript Engine API. If you need it sooner, you can clone the repo and run it locally. You can read about how to do that here.
What does the update schedule look like? Does it generally happen every few weeks or is it an every six months thing?
Normally I will release on weekends, but I’m traveling tomorrow thru next week. Earliest I can push the next point release (with confidence) is May 31st.
The 31st is absolutely fantastic, I just wanted to know if it was going to be several months ![]()
Version 4.1.8 is released! Everything should be live now.
Thank you so much!! We will give it a try right away. This is phenomenal, great work ![]()
I was just trying the new update, and it does seem to be loading the stock and tools correctly for CAM now. However, I keep getting this error:
Kiri:Moto Error: invalid z bottom 1 >= bounds z max 1
I got the settings that I’m using from the gridspace server for the same file and they seem to be working there. Any idea of what might be causing this error?
Yep. That bit isn’t quite fixed. it’s a part of the code tied to the web interface, which isn’t loaded in the engine. Fixing it would require a bunch of refactoring and code digging. For now you can just set the camZBottom to the negative of your part height, as is done in the CAM example.
This is generally working great ![]()
Thank you for the fix!
I have one more question that I’ve been trying to figure out and not making much progress.
The issue is that I can generate gcode great, but the cut is always twice as deep as my part and has two times as many passes.
This should be a single full depth pass, but is instead two passes each with the full depth.
I’m sure that I am doing something silly and obvious, but I can’t for the life of me figure out what it is.
Does anyone have any ideas for what setting could cause this?
Right now I have:
kiriEngine
.setListener((message) => {
console.log("Kiri:Moto Message:", message);
})
.load(stlUrl)
.then((eng) => {
return eng.move(centerPos[0],centerPos[1],0);//Move the model to line up with where the parts were before
})
.then((eng) => {
// console.log("Kiri:Moto STL loaded successfully");
return eng.setMode("CAM");
})
.then((eng) =>{
const bounds = eng.widget.getBoundingBox();
const x = bounds.max.x - bounds.min.x;
const y = bounds.max.y - bounds.min.y;
const z = bounds.max.z - bounds.min.z;
eng.setStock({
x: x + 10,
y: y + 10,
z: z,
center: {
x: x/2, //I'm not sure this is right. We might need to actually find the middle of the bounds
y: y/2,
z: z/2,
},
});
return eng;
})
.then((eng) =>
eng.setTools([
{
id: 1000,
number: 1,
type: "endmill",
name: "end 1/4",
metric: false,
shaft_diam: toolSize,
shaft_len: 1,
flute_diam: 0.25,
flute_len: 2,
taper_tip: 0,
},
])
)
.then((eng) => {
const bounds = eng.widget.getBoundingBox();
const z = bounds.max.z - bounds.min.z;
eng.setProcess({
processName: "default",
camLevelTool: 1000,
camLevelSpindle: 1000,
camLevelOver: 0.5,
camLevelSpeed: 1000,
camLevelDown: 0,
camLevelStock: true,
camRoughTool: 1000,
camRoughSpindle: 1000,
camRoughDown: z / passes,
camRoughOver: 0.4,
camRoughSpeed: speed,
camRoughPlunge: 250,
camRoughStock: 0,
camRoughStockZ: 0,
camRoughAll: true,
camRoughVoid: false,
camRoughFlat: true,
camRoughTop: true,
camRoughIn: true,
camRoughOn: true,
camRoughOmitVoid: false,
camOutlineTool: 1000,
camOutlineSpindle: 1000,
camOutlineTop: true,
camOutlineDown: z / passes,
camOutlineOver: 0.4,
camOutlineOverCount: 1,
camOutlineSpeed: speed,
camOutlinePlunge: 250,
camOutlineWide: false,
camOutlineDogbone: true,
camOutlineOmitThru: false,
camOutlineOmitVoid: false,
camOutlineOut: true,
camOutlineIn: false,
camOutlineOn: true,
camContourTool: 1000,
camContourSpindle: 1000,
camContourOver: 0.5,
camContourSpeed: speed,
camContourAngle: 85,
camContourLeave: 0,
camContourReduce: 2,
camContourBottom: false,
camContourCurves: false,
camContourIn: false,
camContourXOn: true,
camContourYOn: true,
camLatheTool: 1000,
camLatheSpindle: 1000,
camLatheOver: 0.1,
camLatheAngle: 1,
camLatheSpeed: 500,
camLatheLinear: true,
camTolerance: 0,
camTraceTool: 1000,
camTraceSpindle: 1000,
camTraceType: "follow",
camTraceOver: 0.5,
camTraceDown: 0,
camTraceThru: 0,
camTraceSpeed: speed,
camTracePlunge: 200,
camTraceOffOver: 0,
camTraceDogbone: false,
camTraceMerge: true,
camTraceLines: false,
camTraceZTop: 0,
camTraceZBottom: 0,
camPocketSpindle: 1000,
camPocketTool: 1000,
camPocketOver: 0.25,
camPocketDown: 1,
camPocketSpeed: speed,
camPocketPlunge: 200,
camPocketExpand: 0,
camPocketSmooth: 0,
camPocketRefine: 20,
camPocketFollow: 5,
camPocketContour: false,
camPocketEngrave: false,
camPocketOutline: false,
camPocketZTop: 0,
camPocketZBottom: 0,
camDrillTool: 1000,
camDrillSpindle: 1000,
camDrillDownSpeed: 250,
camDrillDown: 5,
camDrillDwell: 250,
camDrillLift: 2,
camDrillMark: false,
camDrillingOn: false,
camRegisterSpeed: 1000,
camRegisterThru: 5,
camFlipAxis: "X",
camFlipOther: "",
camLaserEnable: ["M321"],
camLaserDisable: ["M322"],
camLaserOn: ["M3"],
camLaserOff: ["M5"],
camLaserSpeed: 100,
camLaserPower: 1,
camLaserAdaptive: false,
camLaserAdaptMod: false,
camLaserFlatten: false,
camLaserFlatZ: 0,
camLaserPowerMin: 0,
camLaserPowerMax: 1,
camLaserZMin: 0,
camLaserZMax: 0,
camTabsWidth: 5,
camTabsHeight: 5,
camTabsDepth: 5,
camTabsMidline: false,
camDepthFirst: false,
camEaseDown: false,
camEaseAngle: 10,
camOriginTop: true,
camZAnchor: "middle",
camZOffset: 0,
camZTop: 0,
camZBottom: -z/2,
camZClearance: 1,
camZThru: 0,
camFastFeed: 6000,
camFastFeedZ: 300,
camFlatness: 0.001,
camContourBridge: 0,
camStockX: 20,
camStockY: 5,
camStockZ: 5,
camStockOffset: true,
camStockClipTo: false,
camStockIndexed: false,
camStockIndexGrid: true,
camIndexAxis: 0,
camIndexAbs: true,
camConventional: false,
camOriginCenter: false,
camOriginOffX: 0,
camOriginOffY: 0,
camOriginOffZ: 0,
outputInvertX: false,
outputInvertY: false,
camExpertFast: false,
camTrueShadow: false,
camForceZMax: false,
camFirstZMax: false,
camToolInit: true,
camFullEngage: 0.8,
ops: [
{
type: "outline",
tool: 1000,
spindle: 1000,
step: z / passes,
steps: 1,
down: z / passes,
rate: speed,
plunge: 250,
dogbones: true,
omitvoid: false,
omitthru: false,
outside: true,
inside: false,
wide: false,
top: true,
ov_topz: 0,
ov_botz: 0,
ov_conv: false,
},
{
type: "|",
},
],
op2: [],
camDrillThru: 5,
camDrillPrecision: 1,
"~camConventional": false,
})
return eng;
})
.then((eng) =>
eng.setDevice({
mode: "CAM",
internal: 0,
bedHeight: 2.5,
bedWidth: 10000,
bedDepth: 10000,
maxHeight: 150,
originCenter: false,
spindleMax: 0,
gcodePre: [
"G21 ; set units to MM (required)",
"G90 ; absolute position mode (required)",
],
gcodePost: ["M30 ; program end"],
gcodeDwell: ["G4 P{time} ; dwell for {time}ms"],
gcodeSpindle: [],
gcodeChange: ["M6 T{tool} ; change tool to '{tool_name}'"],
gcodeFExt: "nc",
gcodeSpace: true,
gcodeStrip: true,
new: false,
deviceName: "Any.Generic.Grbl",
imageURL: "",
useLaser: false,
})
)
.then((eng) => eng.slice())
.then((eng) => eng.prepare())
.then((eng) => eng.export())
.then((gcode) => {
gcodeCallback(gcode); // Only call the callback, don't download
})
Thanks you!
Thanks for the question.
I can’t test the code you provided, without more context. It’s missing a definition for kiriEngine, stlUrl, and centerPos though there might be more.
If you can show me how to run this, I’d be happy to debug with you.
