Forum Replies Created
-
AuthorPosts
-
jlauerMember
Hey all, for what it’s worth, I got intrigued by this problem to get ChiliPeppr to do on-the-fly Gcode conversion as you send your job to a 4 pulley system. I did a Google Hangout with Jordan to talk through it. I did a bit more work after the Hangout to figure out the final calculations of a 4 pulley system to calculate the length of wire needed for a 4 pulley system to achieve an XYZ coordinate.
Here’s the code that calculates the length with a sample image of what I’m calculating:
// To achieve a floating/hanging object at a sample position of 6,2,3 var x = 6; var y = 2; var z = 3; // what are the positions of each corner for the pulleys so we can calc var fl_pos = {x:0,y:0,z:10}; var bl_pos = {x:0,y:10,z:10}; var br_pos = {x:10,y:10,z:10}; var fr_pos = {x:10,y:0,z:10}; // convert XYZ cartesion coordinates to XYZA (fl,bl,br,fr) pulley lengths // fl=front left, bl=back left, br=back right, fr=front right // Find hypotenuse length for fl,bl,br,fr in xy plane var fl_xy_hyp = Math.sqrt((x * x) + (y * y)); var bl_xy_hyp = Math.sqrt((x * x) + ((bl_pos.y - y) * (bl_pos.y - y))); var br_xy_hyp = Math.sqrt(((br_pos.x - x) * (br_pos.x - x)) + ((br_pos.y - y) * (br_pos.y - y))); var fr_xy_hyp = Math.sqrt(((fr_pos.x - x) * (fr_pos.x - x)) + (Math.abs(fr_pos.y - y) * Math.abs(fr_pos.y - y))); // Find hypotenuse length for z plane var fl_hyp = Math.sqrt((fl_xy_hyp * fl_xy_hyp) + ((fl_pos.z - z) * (fl_pos.z - z))); var bl_hyp = Math.sqrt((bl_xy_hyp * bl_xy_hyp) + ((bl_pos.z - z) * (bl_pos.z - z))); var br_hyp = Math.sqrt((br_xy_hyp * br_xy_hyp) + ((br_pos.z - z) * (br_pos.z - z))); var fr_hyp = Math.sqrt((fr_xy_hyp * fr_xy_hyp) + ((fr_pos.z - z) * (fr_pos.z - z))); console.log("Pulley len FL:", fl_hyp, "len BL:", bl_hyp, "len BR:", br_hyp, "len FR:", fr_hyp);
Now, if that code is good, you can paste in this entire macro and run it. It will attach to the Gcode send event. Rewrite the gcode to XYZA and you should get your steppers unreeling the correct amount of wire. I mapped X to the front-left pulley, Y to back-left pulley, Z to back-right pulley, and A to front-right pulley. The A would still have to get configured to counter-act the fact that it’s set for angles rather than linear coordinates. I still don’t have that one figured out, but Alden gave some pointers.
// rewrite g-code to 4axis pulley system var myMacro = { init: function() { // Uninit previous runs to unsubscribe correctly, i.e. // so we don't subscribe 100's of times each time we modify // and run this macro if (window["myMacro"]) { macro.status("This macro was run before. Cleaning up..."); window["myMacro"].uninit(); } macro.status("Starting watch on pulley rewrite macro"); // subscribe to JSON send at a higher priority than the default // so we can intercept these pubsub's before they go to the TinyG // cuz we're going to rewrite them chilipeppr.subscribe('/com-chilipeppr-widget-serialport/jsonSend', this, this.onJsonSend, 5); // store macro in window object so we have it next time thru window["myMacro"] = this; // get 3d coordinates by asking the 3d viewer to give them to us // we'll get this.obj3d set for us so we can use it later this.getXyzCoords(); }, uninit: function() { macro.status("Uninitting macro."); chilipeppr.unsubscribe("/com-chilipeppr-widget-serialport/jsonSend", this.onJsonSend); }, onJsonSend: function(data) { console.group('pulley rewrite'); console.log(data); // if the data is an array, then return immediately because we only want to do a rewrite // when jsonSend is individual lines, not when its a multiline array object. // this might seem odd why, but chilipeppr sends lines individually at first and does // it's own ganging up if user picked "multi-line" mode, so let's not rewrite stuff // over and over. just know that if you look for a single line you're safe. if (Array.isArray(data)) { console.log("data was an array, so returning immediately cuz don't want to modify arrays of jsonData"); console.groupEnd(); return; } // extract the line from the ID which is of the form "g45" for line 45 var line = parseInt(data.Id.replace(/g/, "")); // get xyz coords and cleaned up meta data for gcode from the 3d viewer parsed data var coord = this.getXyzCoordsForLine(line); console.log("xyz coords for line:", line, coord); // check if we have a cmd and if it is a G0 or G1, otherwise return if ('cmd' in coord.meta.args && coord.meta.args.cmd.match(/g1|g0/i)) { console.log("this is a command we want to process. good."); } else { console.log("This gcode line did not contain a G0 or G1 command, so not rewriting"); console.groupEnd(); return; } var cmd = coord.meta.args.cmd; // get simple vars for xyz var x = coord.end.x; var y = coord.end.y; var z = coord.end.z; //var x = 6; //var y = 2; //var z = 3; // what are the positions of each corner for the pulleys so we can calc var fl_pos = {x:0,y:0,z:10}; var bl_pos = {x:0,y:10,z:10}; var br_pos = {x:10,y:10,z:10}; var fr_pos = {x:10,y:0,z:10}; // convert XYZ cartesion coordinates to XYZA (fl,bl,br,fr) pulley lengths // fl=front left, bl=back left, br=back right, fr=front right // Find hypotenuse length for fl,bl,br,fr in xy plane var fl_xy_hyp = Math.sqrt((x * x) + (y * y)); var bl_xy_hyp = Math.sqrt((x * x) + ((bl_pos.y - y) * (bl_pos.y - y))); var br_xy_hyp = Math.sqrt(((br_pos.x - x) * (br_pos.x - x)) + ((br_pos.y - y) * (br_pos.y - y))); var fr_xy_hyp = Math.sqrt(((fr_pos.x - x) * (fr_pos.x - x)) + (Math.abs(fr_pos.y - y) * Math.abs(fr_pos.y - y))); // Find hypotenuse length for z plane var fl_hyp = Math.sqrt((fl_xy_hyp * fl_xy_hyp) + ((fl_pos.z - z) * (fl_pos.z - z))); var bl_hyp = Math.sqrt((bl_xy_hyp * bl_xy_hyp) + ((bl_pos.z - z) * (bl_pos.z - z))); var br_hyp = Math.sqrt((br_xy_hyp * br_xy_hyp) + ((br_pos.z - z) * (br_pos.z - z))); var fr_hyp = Math.sqrt((fr_xy_hyp * fr_xy_hyp) + ((fr_pos.z - z) * (fr_pos.z - z))); console.log("Pulley len FL:", fl_hyp, "len BL:", bl_hyp, "len BR:", br_hyp, "len FR:", fr_hyp); var gcode = cmd + " X" + fl_hyp + " Y" + bl_hyp + " Z" + br_hyp + " A" + fr_hyp; console.log("Final gcode:", gcode); // see if there was a feedrate if ('f' in coord.meta.args) { console.log("there was a feedrate:", coord.meta.args.f); gcode += " F" + coord.meta.args.f; } gcode += "\n"; //republish the gcode command that was intercepted var obj = {D: gcode, Id: data.Id}; // unsubscribe so that we don't get our own rewritten gcode coming back to us chilipeppr.unsubscribe('/com-chilipeppr-widget-serialport/jsonSend', this.onJsonSend); // send the gcode off as if nothing really changed, even tho we completely rewrote it chilipeppr.publish('/com-chilipeppr-widget-serialport/jsonSend', obj); // resubscribe immediately so we can rewrite the next line of gcode chilipeppr.subscribe('/com-chilipeppr-widget-serialport/jsonSend', this, this.onJsonSend, 5); console.groupEnd(); return false; }, obj3d: null, getXyzCoords: function() { chilipeppr.subscribe("/com-chilipeppr-widget-3dviewer/recv3dObject", this, this.getXyzCoordsRecv3dObj); chilipeppr.publish("/com-chilipeppr-widget-3dviewer/request3dObject", ""); }, getXyzCoordsRecv3dObj: function(obj3d) { console.log("Got our 3d obj. Line count:", obj3d.userData.lines.length); this.obj3d = obj3d; // unsub so we don't get anymore callbacks on this chilipeppr.unsubscribe("/com-chilipeppr-widget-3dviewer/recv3dObject", this.getXyzCoordsRecv3dObj); }, getXyzCoordsForLine: function(line) { console.log("getXyzCoordsForLine. line:", line); var ret = { start: { index: null, x: null, y: null, z: null }, end: { index: null, x: null, y: null, z: null }, meta: null }; var indx = line - 2; if (indx < 0) indx = 0; ret.start.index = indx; ret.start.x = this.obj3d.userData.lines[indx].p2.x; ret.start.y = this.obj3d.userData.lines[indx].p2.y; ret.start.z = this.obj3d.userData.lines[indx].p2.z; indx = line - 1; ret.end.index = indx; ret.end.x = this.obj3d.userData.lines[indx].p2.x; ret.end.y = this.obj3d.userData.lines[indx].p2.y; ret.end.z = this.obj3d.userData.lines[indx].p2.z; ret.meta = this.obj3d.userData.lines[indx]; return ret; } } myMacro.init();
jlauerMemberHey Jordan,
Could you email me that macro we were working on? I think I can tweak it quick to get it wrapped.
-John
jlauerMemberHi inacio,
Want to jump on a Google hangout real quick? I’d like to perhaps give some ideas on how to do this in ChiliPeppr. I think the code will be easier and you’ll gain all the benefits of the 3D viewer and the rest of the community being able to benefit off your work. I could get you started on how to intercept the Gcode and convert to your 4 axis pulley system. I could do it right now if you’re available. I’m jlauer12@gmail.com on Google Hangouts.
-John
jlauerMemberAlden, did you guys do the on-the-fly rewriting of the Gcode like I’m suggesting? Or did you do all the Gcode from scratch? The reason I ask is that if you do on-the-fly by intercepting /jsonSend you could even do jogging with the machine. I suppose though the XYZ coords coming back to move the toolhead in the 3D viewer would be transposed and that would require additional pubsub rewriting, but that actually wouldn’t be too hard.
jlauerMemberHey Matt,
I do some laser engraving/cutting but use around a 3W diode, so I’m guessing you’re using a 40W CO2 which can cut a lot more stuff. The key trick is using the M3/M5 commands for spindle on/off to instead trigger your laser. There’s also the other trick of controlling an Arduino in parallel to the TinyG movements. This trick additionally uses the Z axis value to decide when to turn the laser on/off instead of M3/M5 (this can create the ability to use more Gcode workflow tools to generate your laser commands). You can see how I’m doing it in the laser soldering video with TinyG. https://www.youtube.com/watch?v=T2h7hagVfnA
If you need super fine toggling of the laser for imprinting images that is a tougher problem as you have to sync the TinyG moves and the laser toggling at a super high rate. I think this could be done by soldering to the “step” pin on the A axis (or other) and setting the TinyG steps/mm to be your toggle setting, i.e. if you want to toggle the laser on/off 1000 times per second and your feedrate is 1mm/sec you can get 1000 on/off’s per mm. Then you have to figure out how to setup the A axis correctly for the correct steps to correspond to your engraving. If this is your approach you could create a widget in ChiliPeppr and a new workspace where you drop-in that widget that intercepts the Gcode, calculates the A axis value, and the rewrites the Gcode.
-John
- This reply was modified 10 years, 1 month ago by jlauer.
jlauerMemberThis sounds like a really fun project. I’d love to help get you started because I think 95% of what you need to get going could be solved by ChiliPeppr. I envision you creating a new widget called “WireBot” that you drop into ChiliPeppr. You write it in Javascript by forking an existing widget like the “Laser Solder” widget and then changing/adding all the things you need.
ChiliPeppr already parses all the Gcode into XYZ coordinates. You can see that the Gcode widget knows the XYZ of each move when you mouse over each line. It’s just getting that data by pubsub to the 3D Viewer widget. That’s a standard call your widget can make. Then you could run your equations to figure out the 4 stepper motor moves and just send those to the TinyG via the pubsub call of “com-chilipeppr-widget-serialport/jsonSend” where your Gcode would look something like “G1 X1 Y1 Z1 A1”. Or, you could even just re-write the Gcode at the click of a button to be your final moves. The only downside there is the 3D viewer would look weird. So i suggest an on-the-fly conversion.
Your widget ultimately should just intercept /jsonSend by subscribing at a higher priority and then rewrite the Gcode and resend it to /jsonSend. It could be a super brilliant way to nail this.
BTW, this pubsub model is standard in the software world for creating loosely coupled systems for extensibility. You need that extensibility and it could solve this fast for you.
I’d be up for jumping on a Google Hangout with you to get you started. You should create a new workspace in ChiliPeppr called chilipeppr.com/tinygWireBot.
- This reply was modified 10 years, 1 month ago by jlauer.
jlauerMemberHey James,
I’m in Seattle, so not quite the bay area, but at least same time zone. I’m really early on in thinking through what elements are needed for the Pick and Place project. The part I’m working on right now is a laser solderer. Not sure it’s going to work though. I have the hardware built and now adding a widget to ChiliPeppr to control it. It’s got a PID to control the laser to not overcook the solder using the Melexis MLX90614 infrared heat sensor. I have a USB Microscope mounted to be able to see the process.
So far I don’t need a fiducial for recognition as I already know the location from the PCB Gcode, however I’m keen to see if the fiducial recognition can happen inside ChiliPeppr because it is a fundamental item that will be needed for a lot of things in the future. I have a lot of webcam integration built using WebRTC. The cool thing with WebRTC is you can just grab a frame and then process it as a bitmap to do things like object detection. This blog seems to give a decent rundown on object detection using WebRTC. http://techslides.com/object-detection-with-html5-getusermedia/
-John
jlauerMemberHi James,
I too am trying to create a pick and place machine and it’s partly why I started ChiliPeppr. So, I’d be up for collaborating. The basic model I have in place is that the Serial Port JSON Server can talk to multiple serial ports at the same time from one software interface, i.e. ChiliPeppr. Then you can coordinate commands between multiple TinyG’s and multiple Arduinos or other serial port devices. I have an example of doing so with this Youtube video https://www.youtube.com/watch?v=TiGAtmWwY8E. It works great and is the start of controlling multiple devices at the same time.
I imagine for Pick and Place that the video integration I’ve already done with MultiCam (see the macro in ChiliPeppr / I also show MultiCam in the youtube video above) can be used to do machine vision alignment. Then based on that, commands can be sent to the pick and place steppers to align, rotate, etc. Also commands could get sent to turn on suction, etc like in my Youtube video where i send “laser-on” and “laser-off”. Then XYZ commands can get sent to the main TinyG for placement, again like in the video.
For pick and place, I think we all should work on the vision recognition part including a “thingiverse” type library for the part recognition.
I envision a new Widget or series of Widgets that have the pick and place control parts like what OpenPNP sort of started doing.
jlauerMemberYeah. It’s official. We needed one.
jlauerMemberAnd a Google Plus community page:
https://plus.google.com/communities/104346367498010042037jlauerMemberI mounted them pretty basic right now with tape! However, I was going to mill out some acrylic to better mount them in an exact spot. I bought these on ebay because they were small. http://www.ebay.com/itm/321060396782?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1439.l2649
They’re just ok though. I am having a hard time getting them really close to the spindle due to the height. I may have to put them at an angle which means I’ll have to apply further transformations to them in the 3D viewer to get the image to appear flat.
If you can get the toolhead to align with the video using the control panel I’m not quite done with, then you shouldn’t have to move anything at all due to your offset once you visually line things up.
jlauerMemberHere’s my suggestion using ChiliPeppr. One of the design goals was to let you bind into multiple serial ports at the same time from CP so you could sync your CNC commands with other hardware (thus a hardware fiddle). So, I would setup an Arduino that reads your sensor on your spindle. Then write a tiny bit of code that just spits out the sensor position every 250ms or perhaps when you request it. Then write a macro in CP that binds into the serial port with your sensor.
chilipeppr.subscribe("/com-chilipeppr-widget-serialport/ws/recv", function(data) { if (data.P == "COM4") { // this is data from my Arduino sensor if (data.D.match(/1000/)) { // I'm at 1000rpm, now move Z into aluminum chilipeppr.publish("/com-chilipeppr-widget-serialport/send", "G1 Z-2 F100\n"); } } });
- This reply was modified 10 years, 3 months ago by jlauer.
jlauerMemberSo, you’ll be geeked by the current work on USB microscopes then. I have two attached to my spindle and I’m 80% there on projecting the video into the 3D Viewer at the correct location. You can check out the work in progress.
Client Widget
http://jsfiddle.net/chilipeppr/k9aXL/Server Widget (Run on multiple machines for more cams)
http://jsfiddle.net/chilipeppr/stpbm/Client Widget Merged with 3D Viewer Test
http://jsfiddle.net/chilipeppr/k789v/jlauerMemberI will be setting one up this week. We DEFINITELY need a forum for it. Any suggestions on best forum? I’m pretty Google-centric since it’s on Google App Engine and uses a Google login, but Google’s forum is kinda old feeling and Google+ Pages aren’t ideal for a forum either.
Also, released v1.3 of the Serial Port JSON Server last night. It increases performance and reliability of never losing Gcode ever due to buffer overflows.
-
AuthorPosts