Commits

Elias Bakken committed 4326bbb

Worked on the software. It seems disabling/enabling the steppers is not working properly..

Comments (0)

Files changed (11)

 
 
 RPATH=/home/root/Replicape
-REMOTE=root@192.168.7.2
+REMOTE=root@10.24.2.90
 DPATH=Dist/dist_`date +"%y_%m_%d"`/Replicape
 DNAME=Replicape_rev_A2-`date +"%y_%m_%d"`.tgz
 
 	unzip images/3.2.34.zip
 	cp -r images/3.2.34/ /lib/modules/ 
 
+paddock: 
+	scp Printrun/paddock.py $(REMOTE):$(RPATH)/software/
+
 dist: 
 	mkdir -p $(DPATH)
 	mkdir -p $(DPATH)/software

PCB_rev_A2/Replicape.brd

Binary file modified.

PCB_rev_A2/Replicape.sch

Binary file modified.
 -   3 medium power MOSFETs (PWM controlled) for up to 3 fans/LED strips.  (12V)  
 -   3 analog input ports for thermistors. noise-filtered inputs and option for shielding  
 -   6 inputs for end stops (X, Y, Z).  
--   1 optional Dallas 1W temperature sensor for monitoring the cold end.  
+-   1 bus for Dallas 1W temperature sensor for monitoring the cold end. Many sensors can be added to ne bus.  
 -   Programmable current limits on steppers motor drivers (SMD). No need to manually adjust a pot meter.  
 -   Microstepping individually programmable for each SMD from 1 to 32.  
 -   All steppers are controlled by the Programmable Realtime Unit (PRU) for hard real time operation.  

software/Ethernet.py

 You can use and change this, but keep this heading :)
 '''
 
-#from Gcode import Gcode
 from threading import Thread
 import socket
 import logging
             except socket.error as e:
                 port += 1    
 
-        print "Ethernet bound to port "+str(port)
+        logging.info("Ethernet bound to port "+str(port))
         self.s.listen(backlog)
         self.running = True
         self.debug = 0
     # Loop that gets messages and pushes them on the queue
     def get_message(self):
         while self.running:
-            print "Ethernet listening"
+            logging.info("Ethernet listening")
             self.client, self.address = self.s.accept()
-            print "Ethernet connection accepted"
+            logging.info("Ethernet connection accepted")
             while True:
                 line = ''
-#                ready = select.select([self.client], [], [], 0.25)
-#                if ready[0]:
                 while not "\n" in line:
                     chunk = self.client.recv(1)
                     if chunk == '':
-                        print "Ethernet: Connection reset by Per."
+                        logging.warning("Ethernet: Connection reset by Per.")
                         self.client.close()             
                         break
                     line = line + chunk

software/Extruder.py

 
 from threading import Thread
 import time
+import logging
 
 ''' 
 A heater element that must keep temperature, 
-either an extruder, a HBP or could even be a heated chamer
+either an extruder, a HBP or could even be a heated chamber
 '''
 class Heater(object):
     ''' Init '''
         self.target_temp = 0.0             # Target temperature (Ts). Start off. 
         self.last_error = 0.0              # Previous error term, used in calculating the derivative
         self.error_integral = 0.0          # Accumulated integral since the temperature came within the boudry
-        self.error_integral_limit = 10.0 # Integral temperature boundry
+        self.error_integral_limit = 40.0 # Integral temperature boundry
         self.debug = 0                   # Debug level
         self.P = 1.0                     # Proportional 
         self.I = 0.0                     # Integral 
             integral = self._getErrorIntegral(error)     # Calculate the error integral        
             power = self.P*(error + self.D*derivative + self.I*integral) # The formula for the PID				
             power = max(min(power, 1.0), 0.0)            # Normalize to 0,1
-            self.mosfet.setPower(power)            		 # Update the mosfet
-            if self.debug > 0:            				 # Debug if necessary 
-                print self.name+": Target: %f, Current: %f"%(self.target_temp, self.current_temp),
-                print ", error: %f, power: %f"%(error, power),
-                print ", derivative: %f, integral: %f"%(self.D*derivative, self.I*integral)
+            self.mosfet.setPower(power)            		 # Update the mosfet            
+            log = self.name+": Tgt: %f, Cur: %f"%(self.target_temp, self.current_temp)
+            log += ", Err: %f, Pow: %f"%(error, power)              
+            #if self.name == "Ext1":
+            #    logging.debug(log+", Der: %f, Int: %f"%(self.D*derivative, self.I*integral))
             time.sleep(1)            					 # Wait one second        
         self.disabled = True							 # Signal the disable that we are done
 
             self.error_integral = 0.0
         return self.error_integral
 
-    ''' Set the debuglevel ''' 
-    def debugLevel(self, val):
-        self.debug = val
-
 ''' Subclass for Heater, this is an extruder '''
 class Extruder(Heater):
     def __init__(self, smd, thermistor, mosfet):
 ''' Subclass for heater, this is a Heated build platform '''
 class HBP(Heater):
     def __init__(self, thermistor, mosfet):
-        Heater.__init__(self, thermistor, mosfet, "HBP")
+        Heater.__init__(self, thermistor, mosfet, "HBP ")
         self.enable()
 
 

software/Gcode.py

 You can use and change this, but keep this heading :)
 '''
 
+import logging
+
 # A command received from pronterface or whatever
 class Gcode:
 
         self.debug = 0
         self.answer = "ok"
 
-        if self.debug > 1:           
-            print "Code: '"+str(self.gcode)+"'"
+        logging.debug("Code: '"+str(self.gcode)+"'")
 
     ''' The machinecode '''
     def code(self):
 
     ''' Get the result of the execution '''
     def getAnswer(self):
-        #print self.message + " = " +self.answer
         return self.answer
     
     ''' Set a new answer other than 'ok'  '''

software/Path_planner.py

         a        = self.acceleration*ratio    		                    # Accelleration in m/s/s
         ds       = 1.0/steps_pr_meter                                   # Delta S, distance in meters travelled pr step.         
         if self.pru.is_processing():                                    # If there is currently a segment being processed, 
-            #print "Is processing, angle to prev is "+str(path.angle_to_prev())
+            logging.debug("Is processing, angle to prev is "+str(path.angle_to_prev()))
             u_start  = ratio*path.get_start_speed()                 	    # The end speed, depends on the angle to the next
         else:
-            #print "Nothing processing"
+            logging.debug("Nothing processing")
             u_start = 0
         if self.paths.qsize() > 0:                                      # If there are paths in queue, we do not have to slow down
-            #print "Has followers, angle to follower: "+str(path.angle_to_next()) 
+            logging.debug("Has followers, angle to follower: "+str(path.angle_to_next()))
             u_end    = ratio*path.get_end_speed()                 	    # The start speed. Depends on the angle to the prev.
         else:
-            #print "Nothing on queue"
+            logging.debug("Nothing on queue")
             u_end = 0
 
-        #print "Max speed for "+axis+" is "+str(Vm)
-        #print "Start speed for "+axis+" is "+str(u_start)
-        #print "End speed for "+axis+" is "+str(u_end)
-        #print ""
+        logging.debug("Max speed for "+axis+" is "+str(Vm))
+        logging.debug("Start speed for "+axis+" is "+str(u_start))
+        logging.debug("End speed for "+axis+" is "+str(u_end))
         tm_start = (Vm-u_start)/a					                    # Calculate the time for when max speed is met. 
         tm_end   = (Vm-u_end)/a					                        # Calculate the time for when max speed is met. 
         sm_start = min(u_start*tm_start + 0.5*a*tm_start**2, s/2.0)     # Calculate the distance traveled when max speed is met
         self.clear_events   = []       
         self.ddr_lock       = Lock() 
         self.debug = 2
-    
         self.i = 0
-        #pypruss.modprobe(0x40000)    			        # This only has to be called once pr boot
 
         self.ddr_addr = int(open("/sys/class/uio/uio0/maps/map1/addr","rb").read().rstrip(), 0)
         self.ddr_size = int(open("/sys/class/uio/uio0/maps/map1/size","rb").read().rstrip(), 0)
-        print "The DDR memory reserved for the PRU is "+hex(self.ddr_size)+" and has addr "+hex(self.ddr_addr)
+        logging.info("The DDR memory reserved for the PRU is "+hex(self.ddr_size)+" and has addr "+hex(self.ddr_addr))
 
         ddr_offset     		= self.ddr_addr-0x20000000  # The Python mmap function cannot accept unsigned longs. 
         ddr_filelen    		= self.ddr_size+0x20000000
         data = np.array([pins, delays])		        	    # Make a 2D matrix combining the ticks and delays
         data = list(data.transpose().flatten())     	    # Braid the data so every other item is a pin and delay
         self.pru_data = data   
-        print "add_data"+hex(pins[0])+" "+hex(pins[1])
 
     ''' Check if the PRU has capacity for a chunk of data '''
     def has_capacity_for(self, data_len):
             cap = self.ddr_size-self.ddr_mem_used
         return (cap/2.0 > data_len) 
 
-    ''' Check if the PRU has capacity for a chunk of data '''
+    
     def get_capacity(self):
+        ''' Check if the PRU has capacity for a chunk of data '''
         with self.ddr_lock:
             cap = self.ddr_size-self.ddr_mem_used
         return cap
             
             if cut == 4: 
                 cut = 12                
-            print "Data len is "+str(len(data))+", Cutting the data at "+str(cut)        
+            logging.debug("Data len is "+str(len(data))+", Cutting the data at "+str(cut))
 
             first = struct.pack('L', len(data[4:cut])/8)+data[4:cut]    # Update the loop count
             first += struct.pack('L', DDR_MAGIC)                        # Add the magic number to force a reset of DDR memory counter
-            print "Laying out from "+hex(self.ddr_start)+" to "+hex(self.ddr_start+len(first))
+            logging.debug("Laying out from "+hex(self.ddr_start)+" to "+hex(self.ddr_start+len(first)))
             self.ddr_mem[self.ddr_start:self.ddr_start+len(first)] = first  # Write the first part of the data to the DDR memory.
 
             with self.ddr_lock:
             if len(data[cut:-4]) > 0:                                 # If len(data) == 4, only the terminating zero is present..
                 second = struct.pack('L', (len(data[cut:-4])/8))+data[cut:]     # Add the number of steps in this iteration
                 self.ddr_end = self.DDR_START+len(second)           # Update the end counter
-                print "Second batch starts from "+hex(self.DDR_START)+" to "+hex(self.ddr_end)
+                logging.debug("Second batch starts from "+hex(self.DDR_START)+" to "+hex(self.ddr_end))
                 self.ddr_mem[self.DDR_START:self.ddr_end] = second  # Write the second half of data to the DDR memory.
                 with self.ddr_lock:
                     self.ddr_mem_used += len(second)
                 with self.ddr_lock:
                     self.ddr_mem_used += 4
                 self.ddr_used.put(4)
-                #self.debug = 2
-                print "\tSecond batch skipped, 0 length"            
+                logging.debug("Second batch skipped, 0 length")
         else:
             self.ddr_mem[self.ddr_start:self.ddr_end] = data    # Write the data to the DDR memory. 
             with self.ddr_lock:
                 self.ddr_mem_used += len(data)               
             self.ddr_used.put(len(data)) 		            # update the amount of memory used 
             if self.debug > 0:
-                 print "Pushed "+str(len(data))+" from "+hex(self.ddr_start)+" to "+hex(self.ddr_end)
+                 logging.debug("Pushed "+str(len(data))+" from "+hex(self.ddr_start)+" to "+hex(self.ddr_end))
             
 
         self.ddr_start 		= self.ddr_end-4                    # Update the start of ddr for next time 
                 with self.ddr_lock:
                     self.ddr_mem_used -= ddr                    
                 if self.debug > 0:
-                    print "Popped "+str(ddr)+"\tnow "+hex(self.get_capacity())
+                    logging.debug("Popped "+str(ddr)+"\tnow "+hex(self.get_capacity()))
                 self.ddr_used.task_done()
                 nr_interrupts += 1  
                                    

software/Replicape.py

 from Path import Path
 from Path_planner import Path_planner
     
-logging.basicConfig(level=logging.INFO)
-
-DEVICE_TREE = True
-LCD = False
+logging.basicConfig(level=logging.DEBUG, 
+                    format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
+                    datefmt='%m-%d %H:%M',
+                    filename='/var/log/replicape.log',
+                    filemode='w')
 
 class Replicape:
     ''' Init '''
     def __init__(self):
-        print "Replicape initializing"
-        if LCD: 
-            print "LCD screen present"
+        logging.info("Replicape initializing")
 
         # Make a list of steppers
         self.steppers = {}
 
+        logging.info("Init steppers")
         # Init the 5 Stepper motors (step, dir, fault, DAC channel, name)
         self.steppers["X"] = SMD("GPIO0_27", "GPIO1_29", "GPIO2_4",  0, "X") 
         self.steppers["Y"] = SMD("GPIO1_12", "GPIO0_22", "GPIO2_5",  1, "Y")  
         self.steppers["Z"] = SMD("GPIO0_23", "GPIO0_26", "GPIO0_15", 2, "Z")  
-        self.steppers["E"] = SMD("GPIO1_28", "GPIO1_15", "GPIO2_1",  3, "Ext1")
-        self.steppers["H"] = SMD("GPIO1_13", "GPIO1_14", "GPIO2_2",  4, "Ext2")
+        self.steppers["H"] = SMD("GPIO1_28", "GPIO1_15", "GPIO2_1",  3, "Ext1")
+        self.steppers["E"] = SMD("GPIO1_13", "GPIO1_14", "GPIO2_2",  4, "Ext2")
 
         # Enable the steppers and set the current, steps pr mm and microstepping  
-        self.steppers["X"].setCurrentValue(1.0) # 2A
+        logging.info("Enabling steppers")
+        self.steppers["X"].setCurrentValue(1.0) 
         self.steppers["X"].setEnabled() 
         self.steppers["X"].set_steps_pr_mm(4.3)         
         self.steppers["X"].set_microstepping(2) 
 
-        self.steppers["Y"].setCurrentValue(1.0) # 2A
+        self.steppers["Y"].setCurrentValue(1.0) 
         self.steppers["Y"].setEnabled() 
         self.steppers["Y"].set_steps_pr_mm(4.3)
         self.steppers["Y"].set_microstepping(2) 
 
-        self.steppers["Z"].setCurrentValue(1.5) # 2A
+        self.steppers["Z"].setCurrentValue(1.5) 
         self.steppers["Z"].setEnabled() 
         self.steppers["Z"].set_steps_pr_mm(50)
         self.steppers["Z"].set_microstepping(2) 
 
-        self.steppers["E"].setCurrentValue(1.5) # 2A        
+        self.steppers["E"].setCurrentValue(1.5) 
         self.steppers["E"].setEnabled()
         self.steppers["E"].set_steps_pr_mm(5.0)
         self.steppers["E"].set_microstepping(2)
 
-        # init the 3 thermistors
+        # Find the path of the thermostors
         path = ""
         for dev in os.listdir("/sys/devices/ocp.2/"):
             if dev.startswith("thermistors"):
                 path = "/sys/devices/ocp.2/"+dev+"/"
                 break
 
-        logging.debug("Thermistors are located at "+path)
+        logging.debug("Found thermistors at "+path)
 
-        self.therm_ext1 = Thermistor(path+"AIN4", "MOSFET_Ext_1", "B57560G104F")
-        self.therm_hbp  = Thermistor(path+"AIN6", "MOSFET_HBP", "B57560G104F")
+        # init the 3 thermistors
+        logging.info("Init Thermistors")
+        self.therm_ext1 = Thermistor(path+"AIN4", "MOSFET Ext 1", "B57560G104F")
+        self.therm_hbp  = Thermistor(path+"AIN6", "MOSFET HBP",   "B57560G104F")
+        self.therm_ext2 = Thermistor(path+"AIN5", "MOSFET Ext 2", "B57560G104F")
 
         # init the 3 heaters
         self.mosfet_ext1 = Mosfet(3)
 
         # Make extruder 1
         self.ext1 = Extruder(self.steppers["E"], self.therm_ext1, self.mosfet_ext1)
-        self.ext1.setPvalue(0.5)
-        self.ext1.setDvalue(0.1)     
-        self.ext1.setIvalue(0.001)
+        self.ext1.setPvalue(0.02)
+        self.ext1.setDvalue(0.9)     
+        self.ext1.setIvalue(0.01)
 
         # Make Heated Build platform 
         self.hbp = HBP( self.therm_hbp, self.mosfet_hbp)       
 
         self.path_planner = Path_planner(self.steppers, self.current_pos)         
         self.path_planner.set_acceleration(self.acceleration) 
-        logging.debug("Debug prints to console")
+        logging.info("Replicape ready")
 	
     ''' When a new gcode comes in, excute it '''
     def loop(self):
                     self.ethernet.send_message(gcode.getAnswer())
                 self.commands.task_done()
         except KeyboardInterrupt:
-            print "Caught keyboard interrupt signal, exiting" 
+            logging.info("Caught keyboard interrupt signal, exiting")
             return
         except Exception as e:
-            print "Something whent wrong.."            
-            print traceback.format_exc()
+            logging.error("Something whent wrong..")
+            logging.error(traceback.format_exc())
         finally:			
             self.ext1.disable()            
-            #self.hbp.disable()            
+            self.hbp.disable()            
             self.usb.close() 
             self.pipe.close()
             self.path_planner.exit()   
-            print "Done"
 		
     ''' Execute a G-code '''
     def _execute(self, g):
                 axis = g.tokenLetter(i)                             # Get the axis, X, Y, Z or E
                 smds[axis] = float(g.tokenValue(i))                 # Get tha value, new position or vector             
             path = Path(smds, self.feed_rate, "ABSOLUTE")           # Make a path segment from the axes
-            print "moving to "+str(smds)
+            logging.debug("moving to "+str(smds))
             self.path_planner.add_path(path)                        # Add the path. This blocks until the path planner has capacity
-            
-        elif g.code() == "G29": 
-            print self.current_pos
         elif g.code() == "G90":                                     # Absolute positioning
             self.movement = "ABSOLUTE"
         elif g.code() == "G91":                                     # Relative positioning 
             pass 													
         elif g.code() == "M110":                                    # Reset the line number counter 
             Gcode.line_number = 0       
+        elif g.code() == "M114": 
+             g.setAnswer("ok C: "+' '.join('%s:%s' % i for i in self.current_pos.iteritems()))
         elif g.code() == "M130":                                    # Set PID P-value, Format (M130 P0 S8.0)
             pass
             #if int(self.tokens[0][1]) == 0:
             fan = self.fans[int(g.getValueByLetter("P"))]
             fan.setPWMFrequency(int(g.getValueByLetter("F")))
             fan.setValue(float(g.getValueByLetter("S")))	           
-        elif g.code() == "M142":
-            print "Current pos is "+str(self.current_pos)
         else:
-            print "Unknown command: "+g.message	
+            logging.warning("Unknown command: "+g.message)
    
 r = Replicape()
 r.loop()
 from spi import SPI
 from threading import Thread
 import time
+import logging
 
 # init the SPI for the DAC
 spi2_0 = SPI(1, 0)	
         bytes = []
         for smd in SMD.all_smds:	   
             bytes.append(smd.getState())
+        txt = ", ".join([hex(b) for b in bytes[::-1]])
+        logging.debug("Writing SPI: "+txt)
         spi2_1.writebytes(bytes[::-1])
 
     ''' Init'''
         self.state |= (value << 1)
         self.update()
         self.mmPrStep = 1.0/(self.steps_pr_mm*self.microsteps)
-        if self.debug > 2:
-            print "State is: "+bin(self.state)
-            print "Microsteps: "+str(self.microsteps)
-            print "mmPrStep is: "+str(self.mmPrStep)
+        logging.debug("State is: "+bin(self.state))
+        logging.debug("Microsteps: "+str(self.microsteps))
+        logging.debug("mmPrStep is: "+str(self.mmPrStep))
 
     ''' Current chopping limit (This is the value you can change) '''
     def setCurrentValue(self, iChop):        
 
     ''' Returns the current state '''
     def getState(self):
-        return self.state & 0xFF				# Return the satate of the serial to parallel
+        return self.state & 0xFF				# Return the state of the serial to parallel
 
     ''' Commits the changes	'''
     def update(self):