Elias Bakken avatar Elias Bakken committed f2e53ea

Seems to be working fine now, except some strange bug happening when accessing via Ethernet.

Comments (0)

Files changed (6)

 .PHONY : software firmware eeprom
 
 eeprom:
-	scp tools/replicape.json tools/eeprom_upload.py eeprom/eeprom.js Makefile $(REMOTE):$(RPATH)/eeprom
+	scp eeprom/replicape.json  eeprom/eeprom.js Makefile $(REMOTE):$(RPATH)/eeprom
 	ssh $(REMOTE) 'cd Replicape/eeprom; make eeprom_cat'
 
 eeprom_upload: 

software/Gcode.py

 
     line_number = 0
     ''' Init; parse the token '''
-    def __init__(self, message, printer):
-        self.message = message
+    def __init__(self, packet, printer):
+        self.message = packet["message"]
+        self.prot = packet["prot"]
         self.p = printer		
 
-        self.tokens = message.split(" ")
+        self.tokens = self.message.split(" ")
         if self.tokens[0][0] == "N":                                # Ok, checksum
-            line_num = message.split(" ")[0][1::]
-            cmd = message.split("*")[0]                             # Command
-            csc = message.split("*")[1]                             # Command to compare with
+            line_num = self.message.split(" ")[0][1::]
+            cmd = self.message.split("*")[0]                             # Command
+            csc = self.message.split("*")[1]                             # Command to compare with
             if int(csc) != self.getCS(cmd):
                 print "CRC error!"            
-            message =  message.split("*")[0][(1+len(line_num)+1)::] # Remove crc stuff
+            self.message =  self.message.split("*")[0][(1+len(line_num)+1)::] # Remove crc stuff
             self.line_number = int(line_num)                        # Set the line number
             Gcode.line_number += 1                                  # Increase the global counter 
                     
         # Parse 
-        self.tokens = message.split(" ")    
+        self.tokens = self.message.split(" ")    
         self.gcode = self.tokens.pop(0) # gcode number
         for i, token in enumerate(self.tokens):
             if len(token) == 0:

software/Path_planner.py

 import numpy as np  
 from threading import Thread
 from Pru import Pru
+from NonPru import NonPru
 import Queue
 from collections import defaultdict
 
         self.t           = Thread(target=self._do_work)         # Make the thread
         self.t.start()		                
 
-    ''' Set the acceleration used '''
+    ''' Set the acceleration used ''' # Fix me, move this to path
     def set_acceleration(self, acceleration):
         self.acceleration = acceleration
 
     ''' This loop pops a path, sends it to the PRU 
     and waits for an event '''
     def _do_work(self):
-        events_waiting = 0
         while self.running:       
             try: 
                 path = self.paths.get(timeout = 1)                            # Get the last path added
                 path.set_global_pos(self.current_pos.copy())       # Set the global position of the printer
-                axes_added = 0
                 all_data = {}
                 slowest =  0
                 for axis in path.get_axes():                       # Run through all the axes in the path    
                         all_data[axis] = data                      # Generate the timing and pin data                         
                         slowest = max(slowest, sum(data[1]))                                   
                 
-                for axis in all_data:                         
+                for axis in all_data:                              # Make all axes use the same amount of time
                     packet = all_data[axis]                           
                     delays = np.array(packet[1])
                     diff = (slowest-sum(delays))/len(delays)
                     for j, delay in enumerate(delays):
-                        delays[j] = max(delay+diff, 1.0/10000.0)    # min 0.2ms                     
+                        delays[j] = max(delay+diff, 1.0/10000.0)    # min 0.1ms                     
                     data = (packet[0], delays)  
-                
-                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"]
-                    
-                for axis in all_data:   # Commit the other axes    
+              
+                for axis in all_data:                               # Merge the data from all axes   
                     packet = all_data[axis]
                     z = zip(np.cumsum(packet[1]), packet[0])
                     for item in z:
                     self.pru.add_data(self.pru_data)
                     self.pru.commit_data()                            # Commit data to ddr
 
+
                 self.pru_data = defaultdict(int)                    
                 self.paths.task_done()
                
             except Queue.Empty:
                 pass
 
-    def merge_data(self):
-        self.pru_data        
-
-    def _add_or_append(self, old, ts, pin):
-        if ts == old[-1][0]:
-            return (x, old[-1][1]+y) 
-        return (x, y)
-
-
     ''' Join the thread '''
     def exit(self):
         self.running = False
         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())
             u_start  = ratio*path.get_start_speed()                 	    # The end speed, depends on the angle to the next
         else:
+            #print "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()) 
             u_end    = ratio*path.get_end_speed()                 	    # The start speed. Depends on the angle to the prev.
         else:
+            #print "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 ""
         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
         td          = num_steps/steps_pr_meter                          # Calculate the actual travelled distance        
         if vec < 0:                                                     # If the vector is negative, negate it.      
             td     *= -1.0
-
-        path.set_travelled_distance(axis, td)                           # Set the travelled distance back in the path 
         self.current_pos[axis] += td                                    # Update the global position vector
 
-        #with open(axis+"_delays", "w+") as f:
-        #    f.write(", ".join(map(str, delays)))
-
         return (pins, delays)                                           # return the pin states and the data
 
 
-if __name__ == '__main__':
-    import bbio as io
-    from Smd import SMD
-    from Path import Path
-
-    steppers = {}
-
-    current_pos = {"X": 0.0, "Y": 0.0}
-    # Init the 5 Stepper motors
-    steppers["X"]  = SMD(io.GPIO1_12, io.GPIO1_13, io.GPIO1_7,  7, "X")  # Fault_x should be PWM2A?
-    steppers["Y"]  = SMD(io.GPIO1_31, io.GPIO1_30, io.GPIO1_15, 1, "Y")  
-    path_planner = Path_planner(steppers, current_pos)         
-    path_planner.set_acceleration(0.3) 
 
-    path = Path({"X": 1000.0, "Y": 1000.0}, 3000.0, "RELATIVE")  
-    import profile
-    path_planner.add_path(path)
-    profile.run('path_planner.test()')
-    path_planner.add_path(path)
-    profile.run('path_planner.test2()')
 
+'''
+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()
+'''
 
-    #profile.run('loop_1()')
-    #profile.run('loop_2()')
-
-    print path_planner.pru._sec_to_inst(0.002)
-    print path_planner.pru._sec_to_inst_2(0.002)
-
-
-    #profile.run('path_planner._make_data(path, "X")')
-    path_planner.exit()
-
-
-    
-
+'''
+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"]
+'''    
 class Pru:
     def __init__(self):
         pru_hz 			    = 200*1000*1000             # The PRU has a speed of 200 MHz
-        self.s_pr_inst 		= 1.0/pru_hz                # I take it every instruction is a single cycle instruction
-        self.s_pr_inst_2    = 2.0*(1.0/pru_hz)          # I take it every instruction is a single cycle instruction
-        self.inst_pr_loop 	= 16                        # This is the minimum number of instructions needed to step. 
+        self.s_pr_inst      = 2.0*(1.0/pru_hz)          # I take it every instruction is a single cycle instruction
+        self.inst_pr_loop 	= 42                        # This is the minimum number of instructions needed to step. 
         self.inst_pr_delay 	= 2                         # Every loop adds two instructions: i-- and i != 0            
         self.sec_to_inst_dev = (self.s_pr_inst*2)
         self.pru_data       = []      	    	        # This holds all data for one move (x,y,z,e1,e2)
         self.ddr_start      = self.DDR_START
         self.ddr_nr_events  = self.ddr_addr+self.ddr_size-4
 
-
         with open("/dev/mem", "r+b") as f:	            # Open the memory device
             self.ddr_mem = mmap.mmap(f.fileno(), ddr_filelen, offset=ddr_offset) # mmap the right area            
             self.ddr_mem[self.ddr_start:self.ddr_start+4] = struct.pack('L', 0)  # Add a zero to the first reg to make it wait
     ''' Add some data to one of the PRUs '''
     def add_data(self, data):
         (pins, delays) = data                       	    # Get the data
-        if len(pins) == 0:
-            return 0
         delays = map(self._sec_to_inst, delays)     	    # Convert the delays in secs to delays in instructions
         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
-        if len(self.pru_data) > 0:
-            self.pru_data = self._braid_data(data, self.pru_data)
-        else:
-            self.pru_data = data
-        return 1    
+        self.pru_data = data   
 
     ''' Check if the PRU has capacity for a chunk of data '''
     def has_capacity_for(self, data_len):
         return (self.ddr_used.qsize() > 0)
 
     ''' Commit the data to the DDR memory '''
-    def commit_data(self, two=False):
-        data = struct.pack('L', len(self.pru_data)/2)	    	# Data in string form
+    def commit_data(self):
+        data = struct.pack('L', len(self.pru_data)/2)	    	                # Data in string form
         data += ''.join([struct.pack('L', word) for word in self.pru_data])
         data += struct.pack('L', 0)                             # Add a terminating 0, this keeps the fw waiting for a new command.
 
         self.ddr_end = self.ddr_start+len(data)       
         if self.ddr_end >= self.DDR_END-16:                     # If the data is too long, wrap it around to the start
-            multiple = (self.DDR_END-self.ddr_start)%8          # Find a multiple of 8
-            cut = self.DDR_END-self.ddr_start-multiple-4-8      # The cut must be done after a delay, so a multiple of 8 bytes +/-4
-        
+            multiple = (self.DDR_END-16-self.ddr_start)%8          # Find a multiple of 8: 4*(pins, delays)
+            cut = self.DDR_END-16-self.ddr_start-multiple-4      # The cut must be done after a delay, so a multiple of 8 bytes +/-4
+            
+            if cut == 4: 
+                cut = 12                
+            print "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))
             else:
                 self.ddr_end = self.DDR_START+4
                 self.ddr_mem[self.DDR_START:self.DDR_START+4] = struct.pack('L', 0) # Terminate the first word
-                self.debug = 2
+                with self.ddr_lock:
+                    self.ddr_mem_used += 4
+                self.ddr_used.put(4)
+                #self.debug = 2
                 print "\tSecond batch skipped, 0 length"            
         else:
             self.ddr_mem[self.ddr_start:self.ddr_end] = data    # Write the data to the DDR memory. 
             if ret[0] == [self.dev]:
                 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]            
+                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_used.task_done()
                     nr_interrupts += 1                         
 
-    ''' Wait for an event. The resturn is the number of events that have occured since last check '''
+    ''' Wait for an event. The return is the number of events that have occured since last check '''
     def _wait_for_event(self):
         self.new_events =  struct.unpack("L", os.read(self.dev, 4))[0]
         ret = self.new_events-self.old_events
         pypruss.exit()                                          # Exit, don't know what this does. 
         
     ''' Convert delay in seconds to number of instructions for the PRU '''
-    def _sec_to_inst_2(self, s):					    # Shit, I'm missing MGP for this??
-        inst_pr_step  = s/self.s_pr_inst  		    # Calculate the number of instructions of delay pr step. 
-        inst_pr_step /= 2.0					        # To get a full period, we must divide by two. 
-        inst_pr_step -= self.inst_pr_loop		    # Remove the "must include" number of steps
-        inst_pr_step /= self.inst_pr_delay		    # Yes, this must be right..
-        #inst_pr_step = ((s/self.s_pr_inst)-self.inst_pr_loop)/self.inst_pr_delay
-        if inst_pr_step < 1:
-            inst_pr_step = 1
-        return int(inst_pr_step)			        # Make it an int
-
-    ''' Convert delay in seconds to number of instructions for the PRU '''
     def _sec_to_inst(self, s):					    # Shit, I'm missing MGP for this??
-        inst_pr_step = (int(s/self.s_pr_inst_2)-self.inst_pr_loop)/self.inst_pr_delay
-        if inst_pr_step < 1:
-            inst_pr_step = 1
-        if inst_pr_step == 0xbabe7175:
-            print "\tInst pr step is BABETITS!!!"
-            inst_pr_step = 0xbabe7175-1
+        inst_pr_step = (int(s/self.s_pr_inst)-self.inst_pr_loop)/self.inst_pr_delay
+        if inst_pr_step < 100:
+            #print " <100" 
+            inst_pr_step = 100
         return inst_pr_step
 
-    ''' Braid/merge together the data from the two data sets'''
-    def _braid_data(self, data1, data2):
-        braids = [data1[0] | data2[0]]
-        del data1[0]
-        del data2[0]
-
-        while len(data1) > 1 and len(data2) > 1:                        
-            if data1[0] > data2[0]:                         # If data 1 is bigger, 
-                data1[0]-= data2[0]-self.inst_pr_loop       # remove the delay from data1..
-                if data1[0] < 1:
-                    data1[0] = 1
-                braids += data2[0:2]                        # And insert data2 with 
-                del data2[0:2]                              # Delete the pushed data
-            elif data1[0] < data2[0]:                       # If data 2 is bigger, 
-                data2[0]-= data1[0]-self.inst_pr_loop       # remove the delay from data2..
-                if data2[0] < 1:
-                    data2[0] = 1
-                braids += data1[0:2]                        # And insert data2 with 
-                del data1[0:2]
-            else:
-                braids += [data1[0]]
-                braids += [data1[1] | data2[1]]             # Merge the pins
-                del data1[0:2]
-                del data2[0:2]
-
-        braids += [max(data1[0], data2[0])]
-        del data1[0]
-        del data2[0]        
-        braids += data2
-        braids += data1
-
-        return braids
 
 
 
-'''
-        if two:
-            data = struct.pack('L', len(self.pru_data)/2)	    	# Data in string form
-            #print list(sum(self.pru_data, ()))
-            self.pru_data = [(self._sec_to_inst(x), y) for x, y in self.pru_data]
-            data += ''.join([struct.pack('L', word) for word in list(sum(self.pru_data, ()))])
-            data += struct.pack('L', 0)                     # Add a terminating 0, this keeps the fw waiting for a new command.
-
-        else:
- '''

software/Replicape.py

 from Thermistor import Thermistor
 from Fan import Fan
 from USB import USB
+from Ethernet import Ethernet
 from Gcode import Gcode
 import sys
 from Extruder import Extruder, HBP
         self.steppers["E"]  = 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.0) # 2A
+        self.steppers["X"].setCurrentValue(1.5) # 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.0) # 2A
+        self.steppers["Y"].setCurrentValue(1.5) # 2A
         self.steppers["Y"].setEnabled() 
         self.steppers["Y"].set_steps_pr_mm(5.95)
         self.steppers["Y"].set_microstepping(2) 
         self.fans = {0: self.fan_1, 1:self.fan_2, 2:self.fan_3 }
 
         # Make a queue of commands
-        self.commands = Queue.Queue()
+        self.commands = Queue.Queue(30)
 
         # Set up USB, this receives messages and pushes them on the queue
         self.usb = USB(self.commands)		
+        self.ethernet = Ethernet(self.commands)
 
         # Get all options 
         self.options = Options()
         self.movement = "RELATIVE"
         self.feed_rate = 3000.0
         self.current_pos = {"X":0.0, "Y":0.0, "Z":0.0, "E":0.0}
-        self.acceleration = 300.0/1000.0
+        self.acceleration = 100.0/1000.0
 
         self.path_planner = Path_planner(self.steppers, self.current_pos)         
         self.path_planner.set_acceleration(self.acceleration) 
             while True:                
                 gcode = Gcode(self.commands.get(), self)
                 self._execute(gcode)
-                self.usb.send_message(gcode.getAnswer())
+                if gcode.prot == "USB":
+                    self.usb.send_message(gcode.getAnswer())
+                else:
+                    self.ethernet.send_message(gcode.getAnswer())
                 self.commands.task_done()
         except KeyboardInterrupt:
             print "Caught signal, exiting" 
             for i in range(g.numTokens()):
                 self.steppers[g.tokenLetter(i)].set_microstepping(int(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() == "M101":									# Deprecated 
     	    if ret[0] == [self.tty]:
                 message = self.tty.readline().strip("\n")          
                 logging.debug("Message: "+message+" ("+message.encode("hex")+")")
-                self.queue.put(message)
+                self.queue.put({"message": message, "prot": "USB"})
             
 
     # Send a message		
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.