MrDraw/SkeinPyPy/fabmetheus_utilities/miscellaneous/fabricate/reprap.py
daid 77d04ceab8 Removed patches for different skeinforge versions. Only SF48 now.
Updated build script to create win32/linux/macos versions.
Fixed the defaults to they work with PLA.
Fixed the temperature plugin default "ON" problem.
Removed all profiles except for PLA.
2012-02-10 17:20:03 +01:00

467 lines
15 KiB
Python

"""
pyRepRap is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pyRepRap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pyRepRap. If not, see <http://www.gnu.org/licenses/>.
"""
"""
This is the main user imported module containing all end user functions
"""
# add commands to switch to gcode mode to allow any script using this library to write gcode too.
try:
import serial # Import the pySerial modules.
except:
print('You do not have pySerial installed, which is needed to control the serial port.')
print('Information on pySerial is at:\nhttp://pyserial.wiki.sourceforge.net/pySerial')
import snap
import time
printDebug = False # print debug info
# SNAP Control Commands - Taken from PIC code #
# extruder commands #
CMD_VERSION = 0
CMD_FORWARD = 1
CMD_REVERSE = 2
CMD_SETPOS = 3
CMD_GETPOS = 4
CMD_SEEK = 5
CMD_FREE = 6
CMD_NOTIFY = 7
CMD_ISEMPTY = 8
CMD_SETHEAT = 9
CMD_GETTEMP = 10
CMD_SETCOOLER = 11
CMD_PWMPERIOD = 50
CMD_PRESCALER = 51
CMD_SETVREF = 52
CMD_SETTEMPSCALER = 53
CMD_GETDEBUGINFO = 54
CMD_GETTEMPINFO = 55
# stepper commands #
CMD_VERSION = 0
CMD_FORWARD = 1
CMD_REVERSE = 2
CMD_SETPOS = 3
CMD_GETPOS = 4
CMD_SEEK = 5
CMD_FREE = 6
CMD_NOTIFY = 7
CMD_SYNC = 8
CMD_CALIBRATE = 9
CMD_GETRANGE = 10
CMD_DDA = 11
CMD_FORWARD1 = 12
CMD_BACKWARD1 = 13
CMD_SETPOWER = 14
CMD_GETSENSOR = 15
CMD_HOMERESET = 16
CMD_GETMODULETYPE = 255
# sync modes #
sync_none = 0 # no sync (default)
sync_seek = 1 # synchronised seeking
sync_inc = 2 # inc motor on each pulse
sync_dec = 3 # dec motor on each pulse
snap.localAddress = 0 # local address of host PC. This will always be 0.
#global serialPort
#serialPort = False
def openSerial( port, rate, tout ):
global serialPort
try:
serialPort = serial.Serial( port, rate, timeout = tout )
return True
except 13:
print "You do not have permissions to use the serial port, try running as root"
def closeSerial():
serialPort.close()
# Convert two 8 bit bytes to one integer
def bytes2int(LSB, MSB):
return int( (0x100 * int(MSB) ) | int(LSB) )
# Convert integer to two 8 bit bytes
def int2bytes(val):
MSB = int( ( int(val) & 0xFF00) / 0x100 )
LSB = int( int(val) & 0xFF )
return LSB, MSB
#def loopTest():
# p = snap.SNAPPacket( serial, snap.localAddress, snap.localAddress, 0, 1, [] )
# Scan reprap network for devices (incomplete) - this will be used by autoconfig functions when complete
def scanNetwork():
devices = []
for remoteAddress in range(1, 10): # For every address in range. full range will be 255
print "Trying address " + str(remoteAddress)
p = snap.SNAPPacket( serialPort, remoteAddress, snap.localAddress, 0, 1, [CMD_GETMODULETYPE] ) # Create snap packet requesting module type
#p = snap.SNAPPacket( serialPort, remoteAddress, snap.localAddress, 0, 1, [CMD_VERSION] )
if p.send(): # Send snap packet, if sent ok then await reply
rep = p.getReply()
if rep:
#devices[ rep.dataBytes[1] ] = remoteAddress
devices.append( { 'address':remoteAddress, 'type':rep.dataBytes[1], 'subType':rep.dataBytes[2] } ) # If device replies then add to device list.
else:
"print na"
else:
print "scan no ack"
time.sleep(0.5)
for d in devices:
#now get versions
print "device", d
def getNotification(serialPort):
return snap.getPacket(serialPort)
class extruderClass:
def __init__(self):
self.address = 8
self.active = False
def getModuleType(self): #note: do pics not support this yet? I can't see it in code and get no reply from pic
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_GETMODULETYPE] ) # Create SNAP packet requesting module type
if p.send():
rep = p.getReply()
data = checkReplyPacket( rep, 2, CMD_GETMODULETYPE ) # If packet sent ok and was acknoledged then await reply, otherwise return False
if data:
return data[1] # If valid reply is recieved then return it, otherwise return False
return False
def getVersion(self):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_VERSION] )
if p.send():
rep = p.getReply()
data = checkReplyPacket( rep, 3, CMD_VERSION )
if data:
return data[1], data[2]
return False
def setMotor(self, direction, speed):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [int(direction), int(speed)] ) ##no command being sent, whats going on?
if p.send():
return True
return False
def getTemp(self):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_GETTEMP] )
if p.send():
rep = p.getReply()
data = checkReplyPacket( rep, 2, CMD_GETTEMP )
if data:
return data[1]
return False
def setVoltateReference(self, val):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_SETVREF, int(val)] )
if p.send():
return True
return False
def setHeat(self, lowHeat, highHeat, tempTarget, tempMax):
if self.active:
tempTargetMSB, tempTargetLSB = int2bytes( tempTarget )
tempMaxMSB ,tempMaxLSB = int2bytes( tempMax )
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_SETHEAT, int(lowHeat), int(highHeat), tempTargetMSB, tempTargetLSB, tempMaxMSB, tempMaxLSB] ) # assumes MSB first (don't know this!)
if p.send():
return True
return False
def setCooler(self, speed):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_SETCOOLER, int(speed)] )
if p.send():
return True
return False
def freeMotor(self):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_FREE] )
if p.send():
return True
return False
extruder = extruderClass()
def checkReplyPacket (packet, numExpectedBytes, command):
if packet:
if len( packet.dataBytes ) == numExpectedBytes: # check correct number of data bytes have been recieved
if packet.dataBytes[0] == command: # check reply is a reply to sent command
return packet.dataBytes
return False
class axisClass:
def __init__(self, address):
self.address = address
self.active = False # when scanning network, set this, then in each func below, check alive before doing anything
self.limit = 100000 # limit effectively disabled unless set
#move axis one step forward
def forward1(self):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_FORWARD1] )
if p.send():
return True
return False
#move axis one step backward
def backward1(self):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_BACKWARD1] )
if p.send():
return True
return False
#spin axis forward at given speed
def forward(self, speed):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_FORWARD, int(speed)] )
if p.send():
return True
return False
#spin axis backward at given speed
def backward(self, speed):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_REVERSE, int(speed)] )
if p.send():
return True
return False
#debug only
def getSensors(self):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_GETSENSOR] )
if p.send():
rep = p.getReply()
data = checkReplyPacket( rep, 3, CMD_GETSENSOR ) # replace this with a proper object in SNAP module?
if data:
print data[1], data[2]
return False
#get current axis position
def getPos(self):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_GETPOS] )
if p.send():
rep = p.getReply()
data = checkReplyPacket( rep, 3, CMD_GETPOS )
if data:
pos = bytes2int( data[1], data[2] )
return pos # return value
return False
#set current position (set variable not robot position)
def setPos(self, pos):
if self.active:
posMSB ,posLSB = int2bytes( pos )
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_SETPOS, posMSB, posLSB] )
if p.send():
return True
return False
#power off coils on stepper
def free(self):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_FREE] )
if p.send():
return True
return False
#seek to axis location. When waitArrival is True, funtion does not return until seek is compete
def seek(self, pos, speed, waitArrival = True):
if self.active and pos <= self.limit:
posMSB ,posLSB = int2bytes( pos )
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_SEEK, int(speed), posMSB ,posLSB] )
if p.send():
if waitArrival:
if printDebug: print " wait notify"
notif = getNotification( serialPort )
if notif.dataBytes[0] == CMD_SEEK:
if printDebug: print " valid notification for seek"
else:
return False
if printDebug: print " rec notif"
return True
return False
#goto 0 position. When waitArrival is True, funtion does not return until reset is compete
def homeReset(self, speed, waitArrival = True):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_HOMERESET, int(speed)] )
if p.send():
if waitArrival:
if printDebug: print "reset wait"
notif = getNotification( serialPort )
if notif.dataBytes[0] == CMD_HOMERESET:
if printDebug: print " valid notification for reset"
else:
return False
if printDebug: print "reset done"
return True
return False
def setNotify(self):
#global serialPort
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_NOTIFY, snap.localAddress] ) # set notifications to be sent to host
if p.send():
return True
return False
def setSync( self, syncMode ):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_SYNC, int(syncMode)] )
if p.send():
return True
return False
def DDA( self, speed, seekTo, slaveDelta, waitArrival = True):
if self.active and seekTo <= self.limit:
masterPosMSB, masterPosLSB = int2bytes( seekTo )
slaveDeltaMSB, slaveDeltaLSB = int2bytes( slaveDelta )
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_DDA, int(speed), masterPosMSB ,masterPosLSB, slaveDeltaMSB, slaveDeltaLSB] ) #start sync
if p.send():
if waitArrival:
notif = getNotification( serialPort )
if notif.dataBytes[0] == CMD_DDA:
if printDebug: print " valid notification for DDA" # todo: add actual enforement on wrong notification
else:
return False
return True
return False
def setPower( self, power ):
if self.active:
p = snap.SNAPPacket( serialPort, self.address, snap.localAddress, 0, 1, [CMD_SETPOWER, int( power * 0.63 )] ) # This is a value from 0 to 63 (6 bits)
if p.send():
return True
return False
class syncAxis:
def __init__( self, axis, seekTo, delta, direction ):
self.axis = axis
self.seekTo = seekTo
self.delta = delta
self.direction = direction
if self.direction > 0:
self.syncMode = sync_inc
else:
self.syncMode = sync_dec
class cartesianClass:
def __init__(self):
# initiate axies with addresses
self.x = axisClass(2)
self.y = axisClass(3)
self.z = axisClass(4)
# goto home position (all axies)
def homeReset(self, speed, waitArrival = True):
if self.x.homeReset( speed, waitArrival ): #setting these to true breaks waitArrival convention. need to rework waitArrival and possibly have each axis storing it's arrival flag and pos as variables?
print "X Reset"
if self.y.homeReset( speed, waitArrival ):
print "Y Reset"
if self.z.homeReset( speed, waitArrival ):
print "Z Reset"
# add a way to collect all three notifications (in whatever order) then check they are all there. this will allow symultanious axis movement and use of waitArrival
# seek to location (all axies). When waitArrival is True, funtion does not return until all seeks are compete
# seek will automatically use syncSeek when it is required. Always use the seek function
def seek(self, pos, speed, waitArrival = True):
curX, curY, curZ = self.x.getPos(), self.y.getPos(), self.z.getPos()
x, y, z = pos
if x <= self.x.limit and y <= self.y.limit and z <= self.z.limit:
if printDebug: print "seek from [", curX, curY, curZ, "] to [", x, y, z, "]"
if x == curX or y == curY:
if printDebug: print " standard seek"
self.x.seek( x, speed, True ) #setting these to true breaks waitArrival convention. need to rework waitArrival and possibly have each axis storing it's arrival flag and pos as variables?
self.y.seek( y, speed, True )
else:
if printDebug: print " sync seek"
self.syncSeek( pos, speed, waitArrival )
if z != curZ:
self.z.seek( z, speed, True )
else:
print "Trying to print outside of limit, aborting seek"
# perform syncronised x/y movement. This is called by seek when needed.
def syncSeek(self, pos, speed, waitArrival = True):
curX, curY = self.x.getPos(), self.y.getPos()
newX, newY, nullZ = pos
deltaX = abs( curX - newX ) # calc delta movements
deltaY = abs( curY - newY )
directionX = ( curX - newX ) / -deltaX # gives direction -1 or 1
directionY = ( curY - newY ) / -deltaY
if printDebug: print " dx", deltaX, "dy", deltaY, "dirX", directionX, "dirY", directionY
if printDebug: print " using x master"
master = syncAxis( self.x, newX, deltaX, directionX ) # create two swapable data structures, set x as master, y as slave
slave = syncAxis( self.y, newY, deltaY, directionY )
if slave.delta > master.delta: # if y has the greater movement then make y master
slave, master = master, slave
if printDebug: print " switching to y master"
if printDebug: print " masterPos", master.seekTo, "slaveDelta", slave.delta
slave.axis.setSync( slave.syncMode )
master.axis.DDA( speed, master.seekTo, slave.delta, True )
time.sleep(0.1)
slave.axis.setSync( sync_none )
if printDebug: print " sync seek complete"
# get current position of all three axies
def getPos(self):
return self.x.getPos(), self.y.getPos(), self.z.getPos()
# stop all motors
def stop(self):
self.x.forward( 0 )
self.y.forward( 0 )
self.z.forward( 0 )
# free all motors (no current on coils)
def free(self):
self.x.free()
self.y.free()
self.z.free()
def setPower(self, power):
self.x.setPower( power )
self.y.setPower( power )
self.z.setPower( power )
#def lockout():
#keep sending power down commands to all board every second
cartesian = cartesianClass()
#wait on serial only when after somthing? or do pics send messages without pc request?