PageRenderTime 58ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/skeinforge/miscellaneous/fabricate/extrude.py

https://github.com/clothbot/DotSkeinforge
Python | 389 lines | 377 code | 5 blank | 7 comment | 2 complexity | 3024bb826df07b4294890ab3d892ae90 MD5 | raw file
  1. """
  2. Extrude is a script to display and extrude a gcode file.
  3. It controls the extruder and movement. It can read linear and helical move commands. It saves a log file with the suffix _log.
  4. To run extrude, install python 2.x on your machine, which is avaliable from http://www.python.org/download/
  5. Then in the folder which extrude is in, type 'python' in a shell to run the python interpreter. Finally type 'import extrude' to import
  6. this program. Extrude requires pySerial installed for this module to work. If you are using Fedora it is available on yum
  7. (run "sudo yum install pyserial"). To actually control the reprap requires write access to the serial device, running as root is
  8. one way to get that access.
  9. This example displays and extrudes a gcode file. This example is run in a terminal as root in the folder which contains
  10. Hollow Square.gcode, and extrude.py.
  11. >>> import extrude
  12. Extrude has been imported.
  13. The gcode files in this directory that are not log files are the following:
  14. ['Hollow Square.gcode']
  15. >>> extrude.display()
  16. File Hollow Square.gcode is being displayed.
  17. reprap.serial = serial.Serial(0, 19200, timeout = 60)
  18. reprap.cartesian.x.active = True
  19. reprap.cartesian.y.active = True
  20. reprap.cartesian.z.active = True
  21. reprap.extruder.active = True
  22. reprap.cartesian.x.setNotify()
  23. reprap.cartesian.y.setNotify()
  24. reprap.cartesian.z.setNotify()
  25. reprap.cartesian.x.limit = 2523
  26. reprap.cartesian.y.limit = 2000
  27. reprap.cartesian.homeReset( 200, True )
  28. ( GCode generated by March 29,2007 Skeinforge )
  29. ( Extruder Initialization )
  30. M100 P210
  31. M103
  32. reprap.extruder.setMotor(reprap.CMD_REVERSE, 0)
  33. ..
  34. many lines of gcode and extruder commands
  35. ..
  36. reprap.cartesian.homeReset( 600, True )
  37. reprap.cartesian.free()
  38. The gcode log file is saved as Hollow Square_log.gcode
  39. >>> extrude.displayFile("Hollow Square.gcode")
  40. File Hollow Square.gcode is being displayed.
  41. ..
  42. The gcode log file is saved as Hollow Square_log.gcode
  43. >>> extrude.displayFiles(["Hollow Square.gcode"])
  44. File Hollow Square.gcode is being displayed.
  45. ..
  46. The gcode log file is saved as Hollow Square_log.gcode
  47. >>> extrude.displayText("
  48. ( GCode generated by March 29,2007 Skeinforge )
  49. ( Extruder Initialization )
  50. ..
  51. many lines of gcode
  52. ..
  53. ")
  54. reprap.serial = serial.Serial(0, 19200, timeout = 60)
  55. reprap.cartesian.x.active = True
  56. reprap.cartesian.y.active = True
  57. reprap.cartesian.z.active = True
  58. reprap.extruder.active = True
  59. reprap.cartesian.x.setNotify()
  60. reprap.cartesian.y.setNotify()
  61. reprap.cartesian.z.setNotify()
  62. reprap.cartesian.x.limit = 2523
  63. reprap.cartesian.y.limit = 2000
  64. reprap.cartesian.homeReset( 200, True )
  65. ( GCode generated by March 29,2007 Skeinforge )
  66. ( Extruder Initialization )
  67. M100 P210
  68. M103
  69. reprap.extruder.setMotor(reprap.CMD_REVERSE, 0)
  70. ..
  71. many lines of gcode and extruder commands
  72. ..
  73. reprap.cartesian.homeReset( 600, True )
  74. reprap.cartesian.free()
  75. Note: On my system the reprap is not connected, so I get can not connect messages, like:
  76. >>> extrude.extrude()
  77. File Hollow Square.gcode is being extruded.
  78. reprap.serial = serial.Serial(0, 19200, timeout = 60)
  79. reprap.cartesian.x.active = True
  80. reprap.cartesian.y.active = True
  81. reprap.cartesian.z.active = True
  82. reprap.extruder.active = True
  83. reprap.cartesian.x.setNotify()
  84. Error: Serial timeout
  85. Error: ACK not recieved
  86. ..
  87. On a system where a reprap is connected to the serial port, you should get the following:
  88. >>> extrude.extrude()
  89. File Hollow Square.gcode is being extruded.
  90. ..
  91. The gcode log file is saved as Hollow Square_log.gcode
  92. >>> extrude.extrudeFile("Hollow Square.gcode")
  93. File Hollow Square.gcode is being extruded.
  94. ..
  95. The gcode log file is saved as Hollow Square_log.gcode
  96. >>> extrude.extrudeFiles(["Hollow Square.gcode"])
  97. File Hollow Square.gcode is being extruded.
  98. ..
  99. The gcode log file is saved as Hollow Square_log.gcode
  100. >>> extrude.extrudeText("
  101. ( GCode generated by March 29,2007 Skeinforge )
  102. ( Extruder Initialization )
  103. ..
  104. many lines of gcode
  105. ..
  106. ")
  107. reprap.serial = serial.Serial(0, 19200, timeout = 60)
  108. reprap.cartesian.x.active = True
  109. reprap.cartesian.y.active = True
  110. reprap.cartesian.z.active = True
  111. reprap.extruder.active = True
  112. reprap.cartesian.x.setNotify()
  113. reprap.cartesian.y.setNotify()
  114. reprap.cartesian.z.setNotify()
  115. reprap.cartesian.x.limit = 2523
  116. reprap.cartesian.y.limit = 2000
  117. reprap.cartesian.homeReset( 200, True )
  118. ( GCode generated by March 29,2007 Skeinforge )
  119. ( Extruder Initialization )
  120. M100 P210
  121. M103
  122. reprap.extruder.setMotor(reprap.CMD_REVERSE, 0)
  123. ..
  124. many lines of gcode and extruder commands
  125. ..
  126. reprap.cartesian.homeReset( 600, True )
  127. reprap.cartesian.free()
  128. """
  129. from __future__ import absolute_import
  130. #Init has to be imported first because it has code to workaround the python bug where relative imports don't work if the module is imported as a main module.
  131. import __init__
  132. try:
  133. import serial # Import the pySerial modules.
  134. except:
  135. print('You do not have pySerial installed, which is needed to control the serial port.')
  136. print('Information on pySerial is at:\nhttp://pyserial.wiki.sourceforge.net/pySerial')
  137. from skeinforge_tools.skeinforge_utilities.vector3 import Vector3
  138. from skeinforge_tools.skeinforge_utilities import euclidean
  139. from skeinforge_tools.skeinforge_utilities import gcodec
  140. import math
  141. import os
  142. import reprap # Import the reprap module.
  143. import time
  144. __author__ = "Enrique Perez (perez_enrique@yahoo.com)"
  145. __credits__ = 'greenarrow <http://forums.reprap.org/profile.php?12,81>'
  146. __date__ = "$Date: 2008/21/04 $"
  147. __license__ = "GPL 3.0"
  148. def display( filename = ''):
  149. "Parse a gcode file and display the commands. If no filename is specified, parse all the gcode files which are not log files in this folder."
  150. if filename == '':
  151. displayFiles( getGCodeFilesWhichAreNotLogFiles() )
  152. return
  153. displayFile( filename )
  154. def displayFile( filename ):
  155. "Parse a gcode file and display the commands."
  156. print('File ' + filename + ' is being displayed.')
  157. fileText = gcodec.getFileText( filename )
  158. gcodec.writeFileMessageSuffix( filename, displayText( fileText ), 'The gcode log file is saved as ', '_log')
  159. def displayFiles( filenames ):
  160. "Parse gcode files and display the commands."
  161. for filename in filenames:
  162. displayFile( filename )
  163. def displayText(gcodeText):
  164. "Parse a gcode text and display the commands."
  165. skein = displaySkein()
  166. skein.parseText(gcodeText)
  167. return skein.output
  168. def extrude( filename = ''):
  169. """Parse a gcode file and send the commands to the extruder. If no filename is specified, parse all the gcode files which are not log files in this folder.
  170. This function requires write access to the serial device, running as root is one way to get that access."""
  171. if filename == '':
  172. extrudeFiles( getGCodeFilesWhichAreNotLogFiles() )
  173. return
  174. extrudeFile( filename )
  175. def extrudeFile( filename ):
  176. """Parse a gcode file and send the commands to the extruder.
  177. This function requires write access to the serial device, running as root is one way to get that access."""
  178. print('File ' + filename + ' is being extruded.')
  179. fileText = gcodec.getFileText( filename )
  180. gcodec.writeFileMessageSuffix( filename, extrudeText( fileText ), 'The gcode log file is saved as ', '_log')
  181. def extrudeFiles( filenames ):
  182. """Parse gcode files and send the commands to the extruder.
  183. This function requires write access to the serial device, running as root is one way to get that access."""
  184. for filename in filenames:
  185. extrudeFile( filename )
  186. def extrudeText(gcodeText):
  187. """Parse a gcode text and send the commands to the extruder.
  188. This function requires write access to the serial device, running as root is one way to get that access."""
  189. skein = extrudeSkein()
  190. skein.parseText(gcodeText)
  191. return skein.output
  192. def getGCodeFilesWhichAreNotLogFiles():
  193. "Get gcode files which are not log files."
  194. return gcodec.getFilesWithFileTypeWithoutWords('gcode', ['_log'] )
  195. def getIntegerString( number ):
  196. "Get integer as string."
  197. return str( int( number ) )
  198. class displaySkein:
  199. "A class to display a gcode skein of extrusions."
  200. def __init__( self ):
  201. self.extruderActive = 0
  202. self.feedrateMinute = 200.0
  203. self.oldLocation = None
  204. self.output = ''
  205. def addToOutput( self, line ):
  206. "Add line with a newline at the end to the output."
  207. print(line)
  208. self.output += line + '\n'
  209. def evaluateCommand( self, command ):
  210. "Add an extruder command to the output."
  211. self.addToOutput( command )
  212. def helicalMove( self, isCounterclockwise, splitLine ):
  213. "Parse a helical move gcode line and send the commands to the extruder."
  214. if self.oldLocation == None:
  215. return
  216. location = Vector3( self.oldLocation )
  217. self.setFeedrate( splitLine )
  218. setPointToSplitLine( location, splitLine )
  219. location = location + self.oldLocation
  220. center = Vector3( self.oldLocation )
  221. indexOfR = indexOfStartingWithSecond( "R", splitLine )
  222. if indexOfR > 0:
  223. radius = getDoubleAfterFirstLetter( splitLine[ indexOfR ] )
  224. halfLocationMinusOld = location - self.oldLocation
  225. halfLocationMinusOld *= 0.5
  226. halfLocationMinusOldLength = halfLocationMinusOld.length()
  227. centerMidpointDistance = math.sqrt( radius * radius - halfLocationMinusOldLength * halfLocationMinusOldLength )
  228. centerMinusMidpoint = getRotatedWiddershinsQuarterAroundZAxis( halfLocationMinusOld )
  229. centerMinusMidpoint.normalize()
  230. centerMinusMidpoint *= centerMidpointDistance
  231. if isCounterclockwise:
  232. center.setToVec3( halfLocationMinusOld + centerMinusMidpoint )
  233. else:
  234. center.setToVec3( halfLocationMinusOld - centerMinusMidpoint )
  235. else:
  236. center.x = getDoubleForLetter( "I", splitLine )
  237. center.y = getDoubleForLetter( "J", splitLine )
  238. curveSection = 0.5
  239. center += self.oldLocation
  240. afterCenterSegment = location - center
  241. beforeCenterSegment = self.oldLocation - center
  242. afterCenterDifferenceAngle = getAngleAroundZAxisDifference( afterCenterSegment, beforeCenterSegment )
  243. absoluteDifferenceAngle = abs( afterCenterDifferenceAngle )
  244. steps = int( math.ceil( max( absoluteDifferenceAngle * 2.4, absoluteDifferenceAngle * beforeCenterSegment.length() / curveSection ) ) )
  245. stepPlaneAngle = getPolar( afterCenterDifferenceAngle / steps, 1.0 )
  246. zIncrement = ( afterCenterSegment.z - beforeCenterSegment.z ) / float( steps )
  247. for step in range( 1, steps ):
  248. beforeCenterSegment = getRoundZAxisByPlaneAngle( stepPlaneAngle, beforeCenterSegment )
  249. beforeCenterSegment.z += zIncrement
  250. arcPoint = center + beforeCenterSegment
  251. self.moveExtruder( arcPoint )
  252. self.moveExtruder( location )
  253. self.oldLocation = location
  254. def homeReset( self ):
  255. "Send all axies to home position. Wait until arrival."
  256. homeCommandString = 'reprap.cartesian.homeReset(' + getIntegerString( self.feedrateMinute ) + ', True )'
  257. self.evaluateCommand( homeCommandString )
  258. def linearMove( self, splitLine ):
  259. "Parse a linear move gcode line and send the commands to the extruder."
  260. location = Vector3()
  261. if self.oldLocation != None:
  262. location = self.oldLocation
  263. self.setFeedrate( splitLine )
  264. setPointToSplitLine( location, splitLine )
  265. self.moveExtruder( location )
  266. self.oldLocation = location
  267. def moveExtruder( self, location ):
  268. "Seek to location. Wait until arrival."
  269. moveSpeedString = getIntegerString( self.feedrateMinute )
  270. xMoveString = getIntegerString( location.x )
  271. yMoveString = getIntegerString( location.y )
  272. zMoveString = getIntegerString( location.z )
  273. moveCommandString = 'reprap.cartesian.seek( (' + xMoveString + ', ' + yMoveString + ', ' + zMoveString + '), ' + moveSpeedString + ', True )'
  274. self.evaluateCommand( moveCommandString )
  275. def parseGCode( self, lines ):
  276. "Parse gcode and send the commands to the extruder."
  277. self.evaluateCommand('reprap.serial = serial.Serial(0, 19200, timeout = 60)') # Initialise serial port, here the first port (0) is used.
  278. self.evaluateCommand('reprap.cartesian.x.active = True') # These devices are present in network, will automatically scan in the future.
  279. self.evaluateCommand('reprap.cartesian.y.active = True')
  280. self.evaluateCommand('reprap.cartesian.z.active = True')
  281. self.evaluateCommand('reprap.extruder.active = True')
  282. self.evaluateCommand('reprap.cartesian.x.setNotify()')
  283. self.evaluateCommand('reprap.cartesian.y.setNotify()')
  284. self.evaluateCommand('reprap.cartesian.z.setNotify()')
  285. self.evaluateCommand('reprap.cartesian.x.limit = 2523')
  286. self.evaluateCommand('reprap.cartesian.y.limit = 2000')
  287. self.homeReset() # The module is now ready to receive commands
  288. for line in lines:
  289. self.parseLine(line)
  290. self.homeReset()
  291. self.evaluateCommand('reprap.cartesian.free()') # Shut off power to all motors.
  292. def parseLine( self, line ):
  293. "Parse a gcode line and send the command to the extruder."
  294. self.addToOutput(line)
  295. splitLine = line.split(' ')
  296. if len( splitLine ) < 1:
  297. return 0
  298. firstWord = splitLine[0]
  299. if firstWord == 'G1':
  300. self.linearMove( splitLine )
  301. if firstWord == 'G2':
  302. self.helicalMove( False, splitLine )
  303. if firstWord == 'G3':
  304. self.helicalMove( True, splitLine )
  305. if firstWord == 'M101':
  306. self.extruderActive = 1
  307. self.evaluateCommand('reprap.extruder.setMotor(reprap.CMD_REVERSE, 150)')
  308. if firstWord == 'M103':
  309. self.extruderActive = 0
  310. self.evaluateCommand('reprap.extruder.setMotor(reprap.CMD_REVERSE, 0)')
  311. self.oldActiveLocation = None
  312. def parseText( self, text ):
  313. "Parse a gcode text and evaluate the commands."
  314. textLines = getTextLines( text )
  315. self.parseGCode( textLines )
  316. def setFeedrate( self, splitLine ):
  317. "Set the feedrate to the gcode split line."
  318. indexOfF = indexOfStartingWithSecond( "F", splitLine )
  319. if indexOfF > 0:
  320. self.feedrateMinute = getDoubleAfterFirstLetter( splitLine[ indexOfF ] )
  321. class extrudeSkein( displaySkein ):
  322. "A class to extrude a gcode skein of extrusions."
  323. def evaluateCommand( self, command ):
  324. """Add an extruder command to the output and evaluate the extruder command.
  325. Display the entire command, but only evaluate the command after the first equal sign."""
  326. self.addToOutput( command )
  327. firstEqualIndex = command.find('=')
  328. exec( command )
  329. print('Extrude has been imported.')
  330. print('The gcode files in this directory that are not log files are the following:')
  331. print( getGCodeFilesWhichAreNotLogFiles() )