Need Help Building Wire Bot

Home Forums TinyG TinyG Support Need Help Building Wire Bot

Viewing 15 posts - 1 through 15 (of 15 total)
  • Author
    Posts
  • #6809
    inacio89
    Member

    Yesterday I purchased the hardware needed to begin building my wire bot project. I bought a TinyG CNC controller, four NEMA 17 stepper motors, and a 24V 14.6A power supply. My plan is to mount one stepper motor to all four corners of my room, attach a pulley to each shaft, wrap a spool of wire around each pulley, and suspend an object in the center of my room with the four wires. I will then input a coordinate (x,y,z) and have each motor adjust the amount of wire it pulls in or lets out to reach that coordinate (i.e. a point in space). I have already done the math to determine the length of wire each motor should release or retract for a given coordinate. What I am having trouble understanding is where/how can I input my equation and where/how can I input the x,y,z coordinate? All of the software I’ve found is for specifically for CNC machining; the software sends the Gcode to the CNC machine and the machine begins cutting.

    Please excuse my ignorance, my background is in Mechanical Engineering so programming isn’t my strong suite. Any help/guidance will be greatly appreciated.

    P.S. I’ve read through the TinyG wiki page and it seems like setting up the TinyG will be pretty straight forward. I just need help with the programming side of this project.

    • This topic was modified 9 years, 11 months ago by inacio89.
    #6813
    cmcgrath5035
    Moderator

    I think that to use a stock tinyG, you will have to come up with a program that translates the required moves into GCode.
    You need four independent linear moves, correct?
    The default tinyG can implement three independent linear moves and three independent rotational moves,but only 4 at a time have motor drivers.
    But since all movement is ultimately rotational movement of the stepper, your equations could translate between linear and rotational.
    But, you need 4 moves that are interdependent

    Perhaps use a spreadsheet to create the four wire lengths from the X,Y coordinates of your room? At least for test purposes

    One of many challenges will be figuring out how to coordinate the actions of the motors. You might have to write a movement planner, a series of gcode moves, perhaps providing some slack in some wires to facilitate moves….

    Hmmm, a non-trivial challenge, unless I am missing something.

    #6816
    inacio89
    Member

    cmcgrath5035, yes, I need four independent linear moves.

    I found this on the synthetos website: https://www.synthetos.com/grblshield-wirebot/

    It outlines pretty much what I am attempting to do, except I would like to control four stepper motors instead of three and I am using a a tinyG instead of a grblshield. Riley wrote a Python program that reads Gcode files, transforms them into X,Y and Z wirebot coordinates and sends commands to grbl. The grbl is connected to an Arduino which then communicates with the stepper motors.

    The math is the same as what I did. As you stated, I inputted the equations into an excel sheet with three inputs (x,y,z), which output the length of wire for each motor.

    What I do not understand is how does this Python program communicate with the grbl? Can this python program communicate directly with my tinyG without modifying the code? I do not know how to code in Python.

    Thanks for your help.

    #6825
    cmcgrath5035
    Moderator

    Cool find!
    I took a quick look (not a Python guru) – it appears to me, as I would expect, the Python code is generating G code and sending to GRBL.
    The serial port (on the PC running the Python Code) connects to the GRBL.
    To run this with a tinyG, you would specify a USB interface.

    I did not look deep enough to see how it accepts input from you as to where you want the object to go, what I saw quickly were some ‘test’ routines(pre defined movements).

    I’d suggest you try to get this 3 wire bot running, then decide where to go next.
    As stated above, the 4th axis will be a rotational axis rather than linear, but that is just math.
    To succeed here, you have to do some Python code (or work in another similar language.

    #6830
    jlauer
    Member

    This 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 9 years, 11 months ago by jlauer.
    #6834
    alden
    Member

    jlauer – Yes! That’s what we did for the TinyG pendulum demo. Put all the math transformations in Javascript in Chilipeppr. Works great.

    #6835
    jlauer
    Member

    Alden, 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.

    #6837
    alden
    Member

    I’m not sure, as Riley and Rob did all this work, but I think we did an on-the-fly re-write. All we needed was for the widget to calculate the F word (did I say that?) to set the velocity for the G1 move

    #6850
    inacio89
    Member

    Hey Guys,

    Everything has arrived! I connected the power supply to the TinyG, as well as, all four motors. I first ran the python code from Riley for three motors and it ran fine. I had to modify some of the code from python 2 to 3, but it works fine with three motors now.

    The issue I am having is zeroing the forth motor. I am able to control all four motors using the “G0 X Y Z A” command, but the 4th motor lets out a lot of line in the beginning of each program. Once it lets out a bunch of line, it runs fine, which is why I think the issue has to do with zeroing.

    I am sure that something is wrong with my gcode, I just do not the proper method of zeroing the 4th axis.

    def Zero(self):
            """This is the zeroing function.  This function
            once ran, should return the length of line to (0,0,0) from each vertex"""
            
            print("Zeroing Function Called")
            value = self.baseEQ(self.ZER0)
            print("G92 X%s Y%s Z%s A%s\n" % (value[0],value[1],value[2],value[3]))
            self.s.write(bytes("G92 X%s Y%s Z%s A%s\n" % (value[0],value[1],value[2],value[3]), 'UTF-8')) #this line sends Gcode commands to tinyG
    #6851
    jlauer
    Member

    Hi 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

    #6854
    jlauer
    Member

    Hey Jordan,

    Could you email me that macro we were working on? I think I can tweak it quick to get it wrapped.

    -John

    #6893
    jlauer
    Member

    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:

    sample

    
    // 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();
    • This reply was modified 9 years, 11 months ago by jlauer.
    • This reply was modified 9 years, 11 months ago by jlauer.
    #7597

    Hi John,
    Did this code ever work as designed? I noticed it got into the Chilpeppr tinyg workspace as an example macro. I tried running it with a very simple gcode file and noted the output from the serial port widget. I compared this to the unaltered (pre-macro) output and they are identical. Maybe the serial port widget prints out the serial message as it comes in, prior to being canceled, rewritten and resent?

    FYI, I am not working on a wirebot as such, but I am using a tinyg as the controller for an art installation which has a number of similar characteristics. I need axis remapping, some randomness inserted into the coordinates and a bunch of other things.

    Thank you for making Chilipeppr, by the way. This is an enormous shift in machine control and I am really excited by the possibilities — even if slightly overwhelmed by the many things to learn.

    #7598

    Oh, for what it’s worth, I am seeing one empty “pulley rewrite” console.group show up in the console. It looks like it’s supposed to write out data. The console.groupEnd is never getting called, as subsequent console.log messages are inside the “>pulley rewrite” group.

    #7601
    cmcgrath5035
    Moderator

    You might want to post this as question about CP macros over at

    More CP types hang out there

Viewing 15 posts - 1 through 15 (of 15 total)
  • You must be logged in to reply to this topic.