Grasshopper

algorithmic modeling for Rhino

Has anyone coded an export script for PLT or HPGL in Grasshopper?

I am looking to send 2d lines from Rhino layers to a cutter, which uses a HPGL / PLT language. Has anyone created a GH definition which includes such a script? As I want to refine it. So I can send flattened geometry from a complex 3D model to get cut.

Any language link or code piece appreciated.

J

Views: 3917

Replies to This Discussion

Hi Jonathan,

I've not got to the bottom of the file size problem - the plotter I have has a 4MB internal buffer - but the problem happened when the PLT files got to around 100K in size - so buffer limits or flow control is not the problem.

What was important to me was getting it working - even if its slightly less tidy that 'ideal' right now, it WORKS and I can get on with using the plotter to do vinyl cutting for me. 

What is funny is that even with 40 or more curves fired to the print driver spooler as individual PLT files the ploter is happy to take them all into its buffer - they all drop out of the windows spooler long before the plot of the first couple of curves is done - so the 100K or so limit I was seeing is coming from something else. 

I think there is a way to turn off the shell on command line calls in Python but I only spent five minutes looking for a solution before I decided that it didn't worry me enough to spend any longer looking.

Cheers

DK

Hi Jonathan,

How I would approach the problem is:

- Create a header for the HPGL that includes the pen number you want

- Select the curves for that tool

- Convert the the cuves to HPGL and add to the file

- Save and send file to printer

then repeat the above for each additional pen/tool

The easiest way to separate each set of curves for each pen/tool would be to have them on different layers (Pen1, Pen2, Pen3, etc comes to mind) and use ObjectsByLayer selection to grab them when needed.

Doing the above with my code as a base would be VERY easy (and this is my first ever Python Project).

I would likely start by hand coding some PLT files in notepad and sending those to the plotter via the command line to test they correct action is taking place.

Cheers

DK

 

Thanks, would this file do it?

Attachments:

There are a few non-standard control codes in the header of that file:

IN;PU;
CT1;
SP1;PU;
VF60;
VW40;
VU80;
TR1;
ZP400,0;
ZS60,100;

Does your plotter have a manual that might give a clue to what those do?

You just be able to include those in every file and it will run fine.

I've been using a trial version of a plotter simulation tool called SPLOT - that could be handy for you too:

Cheers

DK

So, just to update everyone and put some records online - I've done a lot work on this code in the last week or so.

Back story is I picked up and old XP based desk top PC to use as a print server for both my plotter/cutter and wide format printer. I had been running the plotter from my main work laptop - a Win10 machine via the plotters USB port. As it turns out you can't get Win XP drivers for this USB connection so I needed another solution.

I tried to use the plotters DB25 serial port connection using an old DB9 to DB25 modem cable I had in my collection = no luck the plotter wouldn't talk. A bit more research and it turns out these plotters need a 'null modem' cross over cable to operate. I found a pic of the correct wiring online and made up my own with some cable and connectors from the local electronics hobby shop.

With this hooked up and using Hyperterminal I was able to fire some codes to the plotter directly and get a response back - winning!

At this point I got my original code working with the 'net use' redirect from LPT1 to COM1.

HOWEVER - being that the plotter was now on a COM port there are a few more interesting things you can do with it - one is being able to read the paper size/cut area from the printer.

So what I needed to to was find a way to send and receive data to/from the plotter using the serial port.

A bit of research into .NET's serial port interface and using a bunch of small pieces of test code I have manged to completely re-jig this driver.

Upgrades include:

- Direct Serial Port comms using Null Modem cable (a USB to serial adaptor + null modem should also work)

- Plot area read from the plotter - a rectangle the size of the plot area is placed on a separate layer and coloured red

- Testing to see if selected plotting curves are both closed and inside of the cutting area - with errors shown and exiting if they are not right.

- After plot 'parking' of the plot head at the end of the cut items + an adjustable offset (currently requires manual resetting of origin on the plotter before for next cut)

Great thing is it is now 100% running within Rhino Python - no DOS command line calls = no flashing up of the CMD wind. Also no temp files needed on the HDD and no limit to number of curves that can be plotted - tested with 200 or so with no issues.

Overall very happy with whole project - have learnt a LOT about Python and .NET interfacing AND ended up with a very handy/useful tool.

Cheers

DK

# This code is a WIP
# It plots directly to a DGI Plotter
# via the serial port

import System.IO.Ports as Ports
import rhinoscriptsyntax as rs
import time

#Some setup values
com_port = 'COM1' #change to match plotter port
baud_rate = 9600 #change to match plotter setting
plotter_step = .025 #mm
finsh_offset = 10 #mm

#Delete old cutting area and cut objects
if rs.IsLayer('Cutting Area'):
rs.PurgeLayer('Cutting Area')
if rs.IsLayer('Cutting Objects'):
rs.PurgeLayer('Cut Objects')


#Setup Serial Port
Myport = Ports.SerialPort(com_port)
Port_Write = Ports.SerialPort.Write
Myport.BaudRate = baud_rate
Myport.ReadTimeout=5000 #5 secs
Myport.Close()
Myport.Open()


#Setup Plotter
Port_Write(Myport, 'PU;PA0,0;IN;\n')
Port_Write(Myport, 'SP1;\n')
Port_Write(Myport, 'PA;\n')
time.sleep(2)

#Read the Paper size from Plotter
Port_Write(Myport, 'OH;') #HPGL read limits code
time.sleep(2)

return1 = ''
papersize = ''
count = 0
char_in_buffer = 0
chars_in_buffer = Ports.SerialPort.BytesToRead.GetValue(Myport)

if chars_in_buffer == 0:
print 'Plotter not ready'
Myport.Close()
exit()

while (count < chars_in_buffer):
return1 = Myport.ReadChar()
papersize = papersize + chr(return1)
count = count + 1


papersize = papersize.split(",")
rect1 = (float(papersize[2])*plotter_step)
rect2 = (float(papersize[3])*plotter_step)

print 'Cutting area = ' + str(rect1) + 'x' + str(rect2)

#place cutting area curve on its own layer, make it red and lock it
plane = rs.WorldXYPlane()
cutting_area = rs.AddRectangle( plane, (rect1), (rect2))
rs.AddLayer (name='Cutting Area', color=(255,0,0), visible=True, locked=True, parent=None)
rs.ObjectLayer(cutting_area, 'Cutting Area')


#get plotting objects


allCurves = rs.GetObjects("Select curves to plot", rs.filter.curve)

#test to see if these are closed curves - exit if not

for curve in allCurves:
test_closed = rs.IsCurveClosed(curve)
if test_closed == 0:
print "One or move of these curves are not closed"
Myport.Close()
exit()

#test to see if these are inside cutting area - exit if not

for curve in allCurves:
test_inside = rs.PlanarClosedCurveContainment(curve, cutting_area)

if test_inside==0 or test_inside==1:
print "One or more of these curves are outside of cut area"
Myport.Close()
exit()

#All ok - convert to points and send data to printer

rs.AddLayer (name='Cut Objects', color=(0,255,0), visible=False, locked=True, parent=None)


for curve in allCurves:

Port_Write(Myport, 'PU;PA;SP1;\n')

polyline = rs.ConvertCurveToPolyline(curve,angle_tolerance=5.0, tolerance=0.025, delete_input=False, min_edge_length=0, max_edge_length=0)
points = rs.CurveEditPoints(polyline)
rs.ObjectLayer(polyline, 'Cut Objects')


# PU to the first point
x = points[0][0]
y = points[0][1]
Port_Write(Myport, 'PU' + str(int(x / plotter_step)) + ',' + str(int(y / plotter_step)) + ';\n')

# PD to every subsequent point
i = 1
while i < len(points):
x = points[i][0]
y = points[i][1]
Port_Write(Myport, 'PD' + str(int(x / plotter_step)) + ',' + str(int(y / plotter_step)) + ';\n')
i += 1

Port_Write(Myport,'PU;\n')

#find the far end of the cut
box = rs.BoundingBox(allCurves)
far_end = str(box[1])
far_end = far_end.split(",")
far_end = far_end[0]
far_end = float(far_end)/plotter_step
far_end = (int(far_end))+ finsh_offset
far_end = str(far_end)
print (far_end)

#return plotter home and close port
Port_Write(Myport, 'PU;PA' + far_end + ',0;IN;\n')
Port_Write(Myport, 'SP1;\n')
Port_Write(Myport, 'PA;\n')
Myport.Close()
time.sleep(10)

Attachments:

So, did some more work on this project today.

I wasn't liking how the code would throw up and exception box on early exit - say if the com port wouldn't open or the plotter wasnt ready.

A bit of research into Pythons exception handling and most of the code now sits inside of:

try:

    ***My code***

except:

    print 'exception message'

Has cleaned up the reactions to the issues quite nicely - actually really liking this language - can see myself using for more tools in the future. Well done on McNeel for choosing this as a scripting language for Rhino.

Anyway - cleaned up code is attached - I've now got two versions, the second one just gets the max plotting area from the plotter and puts it onto the XY work plane so you can check everything will be inside the before plotting/cutting.

I copy these two scripts into a tool bar button:

Left mouse click on the button and it plots, right click gets the plot area.

Cheers all

DK

 

Attachments:

RSS

About

Translate

Search

© 2024   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service