Commits

Elias Bakken  committed 7cebd8e

Added support for H-belt, also removed a bug that caused the machine to stop when executing single steps for positioning due to interrupt being overlooked. Phiu, bang

  • Participants
  • Parent commits 09d51a5

Comments (0)

Files changed (6)

 
 
-RPATH=/home/root/Replicape
-REMOTE=root@10.24.2.124
+RPATH=/home/root/replicape
+REMOTE=root@10.24.2.105
 
 
 .PHONY : software firmware eeprom

File software/Path.py

 
 class Path: 	
     ''' The axes of evil, the feed rate in mm/min and ABS or REL '''
-    def __init__(self, axes, feed_rate, movement):
+    def __init__(self, axes, feed_rate, movement, is_print_segment=True):
         self.axes = axes
         self.feed_rate = feed_rate
         self.movement = movement
         self.global_pos = {"X":0, "Y":0, "Z":0, "E":0} 
         self.actual_travel = axes.copy()
-           
+        self.is_print_segment = is_print_segment         # If this is True, 
+        self.axis_config = "H-belt"                      # If you need to do some sort of mapping, add the branch here. (ex scara arm)
+          
     ''' Set the next path element '''
     def set_next(self, next):
         self.next = next
     ''' Set the previous path element '''
     def set_prev(self, prev):
         self.prev = prev
-
-    ''' Get the length of this path segment '''
-    def get_length(self):      
+    
+    def set_global_pos(self, global_pos, update_next = True):
+        ''' Set the global position for the printer '''
+        self.global_pos = global_pos		
         if "X" in self.axes:
             x = self.axes["X"]/1000.0
             if self.movement == "ABSOLUTE":
                 y -= self.global_pos["Y"]
         else:
             y = 0
-
-        self.length = np.sqrt(x**2+y**2)                             # calculate the hypotenuse to the X-Y vectors, 
-
         if "Z" in self.axes:
             z = self.axes["Z"]/1000.0
             if self.movement == "ABSOLUTE":           
                 z -= self.global_pos["Z"]
-            self.length  = np.sqrt(self.length**2+z**2)                  # Also include the z-travel          
-
+        else:
+            z = 0
+        if "E" in self.axes:
+            e = self.axes["E"]/1000.0
+            if self.movement == "ABSOLUTE":           
+                e -= self.global_pos["E"]
+        else:
+            e = 0
+
+        # implement any transformation. Hipsterbot has an H-type belt, so: 
+        # This was taken from the article "Dynamic modelling of a Two-axis, Parallel H-frame-Type XY Positioning System".
+        if self.axis_config == "H-belt":
+            A = np.matrix('-0.5 0.5; -0.5 -0.5')
+            b = np.array([x, y])
+            X = np.dot(np.linalg.inv(A), b)
+            x = X[0, 0]
+            y = X[0, 1]
+
+        self.vector = {"X":x, "Y":y, "Z":z, "E":e}
+    
+        # Update the "probable" (as in not true) global pos of the next segment. 
+        # This is in order to calculate the angle to it. Thus it need not be exact. 
+        if hasattr(self, 'next'):
+            a = self.global_pos
+            b = self.vector
+            # Do not continue the update beyond the bnext segment
+            self.next.set_global_pos(dict( (n, a.get(n, 0)+b.get(n, 0)) for n in set(a)|set(b) ), False)
+    
+    ''' Get the length of this path segment '''
+    def get_length(self):     
+        x = self.vector["X"]
+        y = self.vector["Y"]
+        z = self.vector["Z"]
+        self.length = np.sqrt(x**2+y**2+z**2)                             # calculate the hypotenuse to the X-Y vectors, 
         return self.length
 
-    ''' Get the length of the axis '''
+    
     def get_axis_length(self, axis):
-        if not axis in self.axes:
-            return 0.0
-        if self.movement == "ABSOLUTE":            
-            return self.axes[axis]/1000.0 - self.global_pos[axis]     
-        else:
-            return self.axes[axis]/1000.0                         # If movement is relative, the vector is already ok. 
+        ''' Get the length of the axis '''
+        return self.vector[axis]
 
     ''' Get the top speed of this segment '''
     def get_max_speed(self):
 
     ''' Return the list of axes '''
     def get_axes(self):
-        return self.axes
+        return { k : v for k,v in self.vector.iteritems() if v != 0 }
 
     ''' set the distance that was actually travelled.. '''
     def set_travelled_distance(self, axis, td):
     def get_travelled_distance(self):
         return self.actual_travel
 
-    ''' Set the global position for the printer '''
-    def set_global_pos(self, global_pos):
-        self.global_pos = global_pos
-
     ''' Return the angle to the next path segment '''
     def angle_to_next(self):
         if not hasattr(self, 'next'):

File software/Path_planner.py

                     diff = (slowest-sum(delays))/len(delays)
                     for j, delay in enumerate(delays):
                         delays[j] = max(delay+diff, 1.0/10000.0)    # min 0.1ms                     
-                    data = (packet[0], delays)  
+                    data = (packet[0], delays)                  
               
                 for axis in all_data:                               # Merge the data from all axes   
                     packet = all_data[axis]
                 if len(self.pru_data) > 0:
                     z = zip(*sorted(self.pru_data.items()))
                     self.pru_data = (list(z[1]), list(np.diff([0]+list(z[0]))))
-
                     while not self.pru.has_capacity_for(len(self.pru_data[0])*8):
-                        time.sleep(0.1)                   
+                        time.sleep(1)              
+         
                     self.pru.add_data(self.pru_data)
                     self.pru.commit_data()                            # Commit data to ddr
 
-
                 self.pru_data = defaultdict(int)                    
                 self.paths.task_done()
                
         return (pins, delays)                                           # return the pin states and the data
 
 
-
-
-'''
-for axis in all_data:
-    stepper = self.steppers[axis]
-    packet = all_data[axis]
-    stepper.add_data(packet)
-    stepper.prepare_move()
-
-for axis in all_data:
-    stepper = self.steppers[axis]
-    stepper.start_move()
-
-for axis in all_data:
-    stepper = self.steppers[axis]
-    stepper.end_move()
-'''
-
-'''
-if "Z" in all_data:     # HACK! The Z-axis cannot be combined with the other data. Somehow it goes backwards...
-    packet = all_data["Z"]      
-    while not self.pru.has_capacity_for(len(packet[0])*8):# Wait until the PRU has capacity for this chunk of data
-        time.sleep(1)                   
-    if self.pru.add_data(packet) > 0:                        
-        self.pru.commit_data() 
-    del all_data["Z"]
-'''    

File software/Pru.py

         pypruss.exec_program(0, "../firmware/firmware_pru_0.bin")	# Load firmware "ddr_write.bin" on PRU 0
         self.t = Thread(target=self._wait_for_events)         # Make the thread
         self.running = True
-        self.t.start()		                
+        self.t.start()		        
 
         logging.debug("PRU initialized")
 
                 self._wait_for_event()
                 pypruss.clear_event(PRU0_ARM_INTERRUPT)			# Clear the event        
                 nr_events = struct.unpack("L", self.ddr_mem[self.DDR_END-4:self.DDR_END])[0]   
-                #if nr_interrupts < nr_events-1:
-                #    print "\tnr_events >> nr_interrutps"
-                while nr_interrupts < nr_events:
-                    ddr = self.ddr_used.get()                       # Pop the first ddr memory amount           
-                    with self.ddr_lock:
-                        self.ddr_mem_used -= ddr                    
-                    if self.debug > 0:
-                        print "Popped "+str(ddr)+"\tnow "+hex(self.get_capacity())
-                    self.ddr_used.task_done()
-                    nr_interrupts += 1                         
+            else:
+                nr_events = struct.unpack("L", self.ddr_mem[self.DDR_END-4:self.DDR_END])[0]
+            while nr_interrupts < nr_events:
+                ddr = self.ddr_used.get()                       # Pop the first ddr memory amount           
+                with self.ddr_lock:
+                    self.ddr_mem_used -= ddr                    
+                if self.debug > 0:
+                    print "Popped "+str(ddr)+"\tnow "+hex(self.get_capacity())
+                self.ddr_used.task_done()
+                nr_interrupts += 1  
+                                   
 
     ''' Wait for an event. The return is the number of events that have occured since last check '''
     def _wait_for_event(self):

File software/Replicape.py

         self.steppers = {}
 
         # Init the 5 Stepper motors
-        self.steppers["X"]  = SMD(io.GPIO1_12, io.GPIO1_13, io.GPIO2_4,  5, "X")  # Fault_x should be PWM2A?
+        self.steppers["X"]  = SMD(io.GPIO1_12, io.GPIO1_13, io.GPIO2_4,  0, "X")  # Fault_x should be PWM2A?
         self.steppers["Y"]  = SMD(io.GPIO1_31, io.GPIO1_30, io.GPIO1_15, 1, "Y")  
         self.steppers["Z"]  = SMD(io.GPIO1_1,  io.GPIO1_2,  io.GPIO0_27, 2, "Z")  
-        self.steppers["E2"]  = SMD(io.GPIO3_21, io.GPIO1_7, io.GPIO2_1,  3, "Ext1")
-        self.steppers["E"]  = SMD(io.GPIO1_14, io.GPIO1_6, io.GPIO2_3,  4, "Ext2")
+        self.steppers["E"] = SMD(io.GPIO3_21, io.GPIO1_7, io.GPIO2_1,  3, "Ext1")
+        self.steppers["F"]  = SMD(io.GPIO1_14, io.GPIO1_6, io.GPIO2_3,  4, "Ext2")
+
+        
 
         # Enable the steppers and set the current, steps pr mm and microstepping  
-        self.steppers["X"].setCurrentValue(1.5) # 2A
+        self.steppers["X"].setCurrentValue(1.0) # 2A
         self.steppers["X"].setEnabled() 
         self.steppers["X"].set_steps_pr_mm(6.105)         
         self.steppers["X"].set_microstepping(2) 
 
-        self.steppers["Y"].setCurrentValue(1.5) # 2A
+        self.steppers["Y"].setCurrentValue(1.0) # 2A
         self.steppers["Y"].setEnabled() 
         self.steppers["Y"].set_steps_pr_mm(5.95)
         self.steppers["Y"].set_microstepping(2) 
         elif g.code() == "M30":                                     # Set microstepping (Propietary to Replicape)
             for i in range(g.numTokens()):
                 self.steppers[g.tokenLetter(i)].set_microstepping(int(g.tokenValue(i)))            
+        elif g.code() == "M31":                                     # Set stepper current limit (Propietery to Replicape)
+            for i in range(g.numTokens()):                         
+                self.steppers[g.tokenLetter(i)].setCurrentValue(float(g.tokenValue(i)))            
         elif g.code() == "M84":                                     # Disable all steppers
             print "Waiting for path planner"
             self.path_planner.wait_until_done()
             print "Path planner done"
             for name, stepper in self.steppers.iteritems():
             	stepper.setDisabled()
+        elif g.code() == "M92": 
+            for i in range(g.numTokens()):                          # Run through all tokens
+                axis = g.tokenLetter(i)                             # Get the axis, X, Y, Z or E
+                self.steppers[axis].set_steps_pr_mm(float(g.tokenValue(i)))        
         elif g.code() == "M101":									# Deprecated 
             pass 													
         elif g.code() == "M103":									# Deprecated

File software/Smd.py

         for smd in SMD.all_smds:	   
             bytes.append(smd.getState())
         spi2_1.writebytes(bytes[::-1])
-        print "wrote "+str(bytes[::-1])
 
     ''' Init'''
     def __init__(self, stepPin, dirPin, faultPin, dac_channel, name):