def __init__(self): np.set_printoptions(precision=2, suppress=True) self._calculate_geometry() self.LIMITS = platform_1dof_limits # max movement in a single dof self.platform_disabled_pos = np.empty( 6) # position when platform is disabled self.platform_disabled_pos.fill(DISABLED_LEN) self.platform_winddown_pos = np.empty( 6) # position for attaching stairs self.platform_winddown_pos.fill(WINDDOWN_LEN) self.isEnabled = False # platform disabled if False self.loaded_weight = PLATFORM_UNLOADED_WEIGHT + DEFAULT_PAYLOAD_WEIGHT self.prev_pos = [0, 0, 0, 0, 0, 0] # requested distances stored here self.requested_pressures = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] self.actual_pressures = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] self.prev_time = time.clock() if IS_SERIAL: # configure the serial connection try: self.ser = serial.Serial(port=OutSerialPort, baudrate=57600, timeout=1) print "Out simulator opened on ", OutSerialPort except: print "unable to open Out simulator serial port", OutSerialPort elif not TESTING: self.FSTs = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.FST_addr = (FST_ip, FST_port) if not OLD_FESTO_CONTROLLER: self.FSTs.bind(('0.0.0.0', 0)) self.FSTs.settimeout(1) # timout after 1 second if no response print "" self.prevMsg = [] self.gui = OutputGui()
class OutputInterface(object): # IS_SERIAL is set True if using serial platform simulator for testing global IS_SERIAL def __init__(self): np.set_printoptions(precision=2, suppress=True) self._calculate_geometry() self.LIMITS = platform_1dof_limits # max movement in a single dof self.platform_disabled_pos = np.empty( 6) # position when platform is disabled self.platform_disabled_pos.fill(DISABLED_LEN) self.platform_winddown_pos = np.empty( 6) # position for attaching stairs self.platform_winddown_pos.fill(WINDDOWN_LEN) self.isEnabled = False # platform disabled if False self.loaded_weight = PLATFORM_UNLOADED_WEIGHT + DEFAULT_PAYLOAD_WEIGHT self.prev_pos = [0, 0, 0, 0, 0, 0] # requested distances stored here self.requested_pressures = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] self.actual_pressures = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] self.pressure_percent = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] self.prev_time = time.clock() self.netlink_ok = False # True if festo responds without error self.ser = None self.monitor_client = None if MONITOR_PORT: self.monitor_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) print "platform monitor output on port", MONITOR_PORT if IS_SERIAL: # configure the serial connection try: self.ser = serial.Serial(port=OutSerialPort, baudrate=57600, timeout=1) print "Serial Output simulator opened on ", OutSerialPort except: print "unable to open Out simulator serial port", OutSerialPort elif not TESTING: self.FSTs = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.FST_addr = (FST_ip, FST_port) if not OLD_FESTO_CONTROLLER: self.FSTs.bind(('0.0.0.0', 0)) self.FSTs.settimeout(1) # timout after 1 second if no response print "" self.prevMsg = [] self.use_gui = False # defualt is no gui self.activate_piston_flag = 0 # park piston is extended when flag set to 1, parked when 0 def init_gui(self, master): self.gui = OutputGui() self.gui.init_gui(master, MIN_ACTUATOR_LEN, MAX_ACTUATOR_LEN) self.use_gui = True def fin(self): """ free resources used by ths module """ if IS_SERIAL: try: if self.ser and self.ser.isOpen(): self.ser.close() except: pass else: if not TESTING: self.FSTs.close() def get_platform_name(self): return PLATFORM_NAME def get_geometry(self): """ get coordinates of fixed and moving attachment points and mid height """ "platform mid height", self.platform_mid_height return base_pos, platform_pos, self.platform_mid_height def get_actuator_lengths(self): return MIN_ACTUATOR_LEN, MAX_ACTUATOR_LEN def get_platform_pos(self): """ get coordinates of fixed platform attachment points """ return platform_pos def get_output_status(self): """ return string describing output status """ if TESTING: return ("Test mode, no output to Festo", "red") if OLD_FESTO_CONTROLLER: return ("Old Festo Controller", "green3") else: if WAIT_FESTO_RESPONSE: ###self._get_pressure() if not self.netlink_ok: return ( "Festo network error (check ethernet cable and festo power)", "red") else: bad = [] if 0 in self.actual_pressures: for idx, v in enumerate(self.actual_pressures): if v == 0: bad.append(idx) if len(bad) == 6: return ("Festo Pressure Zero on all muscles", "red") else: bad_str = ','.join(map(str, bad)) return ("Festo Pressure Zero on muscles: " + bad_str, "red") elif any(p < 10 for p in self.pressure_percent): return ("Festo Pressure is Low", "orange") elif any(p < 10 for p in self.pressure_percent): return ("Festo Pressure is High", "orange") else: return ("Festo Pressure is Good", "green3" ) # todo, also check if pressure is low else: return ("New Festo controller response not enabled", "orange") def get_platform_mid_height(self): """ get actuater lengths in mid (ready for ride) position """ return self.platform_mid_height # height in mm from base at mid position def get_limits(self): """ provide limit of movement in all 6 DOF from imported platform config file """ return self.LIMITS def set_payload(self, payload_kg): """ set passenger weight in killograms """ self.loaded_weight = PLATFORM_UNLOADED_WEIGHT + payload_kg def set_enable(self, state, actuator_lengths): """ enable platform if True, disable if False actuator_lengths are those needed to achieve current client orientation """ if self.isEnabled != state: self.isEnabled = state print "Platform enabled state is", state if state: pass # self._slow_move(self.platform_disabled_pos, actuator_lengths, 1000) else: self.activate_piston_flag = 0 self._slow_move(actuator_lengths, self.platform_disabled_pos, 1000) def move_to_limits(self, pos): """ + or - 1 in [x,y,z,ax,ay,az] moves to that limit, 0 to middle Args: pos is list of translations and rotations """ self.moveTo([p * l for p, l in zip(pos, self.limits)]) def move_to_idle(self, client_pos): self._slow_move(client_pos, self.platform_disabled_pos, 1000) #print "move to idle pos" def move_to_ready(self, client_pos): self._slow_move(self.platform_disabled_pos, client_pos, 1000) #print "move to ready pos" def swell_for_access(self, interval): """ Briefly raises platform high enough to insert access stairs moves even if disabled Args: interval (int): time in ms before dropping back to start pos """ self._slow_move(self.platform_disabled_pos, self.platform_winddown_pos, 1000) time.sleep(interval) self._slow_move(self.platform_winddown_pos, self.platform_disabled_pos, 1000) def park_platform(self, state): if state: self.activate_piston_flag = 0 print "setting flag to activate pistion to 0" else: self.activate_piston_flag = 1 print "setting flag to activate pistion to 1" def move_platform( self, lengths): # lengths is list of 6 actuator lengths as millimeters """ Move all platform actuators to the given lengths Args: lengths (float): numpy array comprising 6 actuator lengths """ clipped = [] for idx, l in enumerate(lengths): if l < MIN_ACTUATOR_LEN: lengths[idx] = MIN_ACTUATOR_LEN clipped.append(idx) elif l > MAX_ACTUATOR_LEN: lengths[idx] = MAX_ACTUATOR_LEN clipped.append(idx) if len(clipped) > 0: pass # print "Warning, actuators", clipped, "were clipped" if self.isEnabled: if IS_SERIAL: self._move_to_serial(lengths) else: self._move_to(lengths) # only fulfill request if enabled """ else: print "Platform Disabled" """ def show_muscles(self, position_request, muscles): if self.use_gui: self.gui.show_muscles(position_request, muscles, self.pressure_percent) if self.monitor_client: # echo position requests to monitor port if enabled xyzrpy = ",".join('%0.3f' % item for item in position_request) lengths = ",".join('%0.1f' % item for item in muscles) msg = "monitor," + xyzrpy + ',' + lengths + '\n' # send pos as mm and radians, actuator lengths as mm self.monitor_client.sendto(msg, MONITOR_ADDR) print msg # private methods def _slow_move(self, start, end, duration): if IS_SERIAL: move_func = self._move_to_serial else: move_func = self._move_to # caution, this moves even if disabled interval = 50 # time between steps in ms steps = duration / interval if steps < 1: self.move(end) else: current = start print "moving from", start, "to", end, "steps", steps delta = [float(e - s) / steps for s, e in zip(start, end)] for step in xrange(steps): current = [x + y for x, y in zip(current, delta)] move_func(copy.copy(current)) self.show_muscles([0, 0, 0, 0, 0, 0], current) time.sleep(interval / 1000.0) def _calculate_geometry(self): # reflect around X axis to generate right side coordinates global base_pos, platform_pos otherSide = copy.deepcopy(base_pos[::-1]) # order reversed for inner in otherSide: inner[1] = -inner[1] # negate Y values base_pos.extend(otherSide) otherSide = copy.deepcopy(platform_pos[::-1]) # order reversed for inner in otherSide: inner[1] = -inner[1] # negate Y values platform_pos.extend(otherSide) base_pos = np.array(base_pos) platform_pos = np.array(platform_pos) # print "\nPlatformOutput using %s configuration" %(PLATFORM_NAME) # print "Actuator lengths: Min %d, Max %d, mid %d" %( MIN_ACTUATOR_LEN, MAX_ACTUATOR_LEN, MID_ACTUATOR_LEN) self.platform_mid_height = platform_mid_height # uncomment this section to plot the array coordinates """ bx= base_pos[:,0] by = base_pos[:,1] plt.scatter(bx,by) px= platform_pos[:,0] py = platform_pos[:,1] plt.axis('equal') plt.scatter(px,py) plt.show() """ # print "base_pos:\n",base_pos # print "platform_pos:\n",platform_pos def _move_to_serial(self, lengths): # msg = "xyzrpy," + ",".join([str(round(item)) for item in lengths]) payload = ",".join('%0.1f' % item for item in lengths) if payload != self.prevMsg: print "lengths: ", payload self.prevMsg = payload if self.ser and self.ser.isOpen(): self.ser.write("xyzrpy," + payload + '\n') # print self.ser.readline() else: print "serial not open" def _move_to(self, lengths): print "lengths:\t ", ",".join(' %d' % item for item in lengths) now = time.clock() timeDelta = now - self.prev_time self.prev_time = now load_per_muscle = self.loaded_weight / 6 # if needed we could calculate individual muscle loads pressure = [] # print "LENGTHS = ",lengths for idx, len in enumerate(lengths): pressure.append( int(1000 * self._convert_MM_to_pressure( idx, len - FIXED_LEN, timeDelta, load_per_muscle))) self._send(pressure) def _convert_MM_to_pressure(self, idx, muscle_len, timeDelta, load): # returns pressure in bar # calculate the percent of muscle contraction to give the desired distance percent = (MAX_MUSCLE_LEN - muscle_len) / float(MAX_MUSCLE_LEN) # check for range between 0 and .25 # print "muscle Len =", muscle_len, "percent =", percent if percent < 0 or percent > 0.25: print "%.2f percent contraction out of bounds for muscle length %.1f" % ( percent, muscle_len) distDelta = muscle_len - self.prev_pos[ idx] # the change in length from the previous position accel = (distDelta / 1000) / timeDelta # accleration units are meters per sec if distDelta < 0: force = load * ( 1 - accel ) # TODO here we assume force is same magnitude as expanding muscle ??? # TODO modify formula for force # pressure = 30 * percent*percent + 12 * percent + .01 # assume 25 Newtons for now pressure = 35 * percent * percent + 15 * percent + .03 # assume 25 Newtons for now if PRINT_MUSCLES: print( "muscle %d contracting %.1f mm to %.1f, accel is %.2f, force is %.1fN, pressure is %.2f" % (idx, distDelta, muscle_len, accel, force, pressure)) else: force = load * (1 + accel) # force in newtons not yet used # TODO modify formula for expansion pressure = 35 * percent * percent + 15 * percent + .03 # assume 25 Newtons for now if PRINT_MUSCLES: print( "muscle %d expanding %.1f mm to %.1f, accel is %.2f, force is %.1fN, pressure is %.2f" % (idx, distDelta, muscle_len, accel, force, pressure)) self.prev_pos[idx] = muscle_len # store the muscle len MAX_PRESSURE = 6.0 MIN_PRESSURE = .05 # 50 millibar is minimin pressure pressure = max(min(MAX_PRESSURE, pressure), MIN_PRESSURE) # limit range return pressure def _send(self, muscle_pressures): self.requested_pressures = muscle_pressures # store this for display if reqiured if not TESTING: try: if not OLD_FESTO_CONTROLLER: muscle_pressures.append(self.activate_piston_flag) print "muscle pressures:", muscle_pressures packet = easyip.Factory.send_flagword(0, muscle_pressures) try: self._send_packet(packet) if WAIT_FESTO_RESPONSE: self.actual_pressures = self._get_pressure() delta = [ act - req for req, act in zip( muscle_pressures, self.actual_pressures) ] # todo - next line needs changing because park flag now appended to list self.pressure_percent = [ int(d * 100 / req) for d, req in zip(delta, muscle_pressures) ] if PRINT_PRESSURE_DELTA: print muscle_pressures, delta, self.pressure_percent except socket.timeout: print "timeout waiting for replay from", self.FST_addr else: for idx, muscle in enumerate(muscle_pressures): maw = int(muscle * 1000) maw = max(min(6000, muscle), 0) # limit range to 0 to 6000 command = "maw" + str(64 + idx) + "=" + str(maw) # print command, command = command + "\r\n" self.FSTs.sendto(command, self.FST_addr) except: e = sys.exc_info()[0] s = traceback.format_exc() print "error sending to Festo", e, s def _send_packet(self, packet): if not TESTING: data = packet.pack() # print "sending to", self.FST_addr self.FSTs.sendto(data, self.FST_addr) if WAIT_FESTO_RESPONSE: # print "in sendpacket,waiting for response..." data, srvaddr = self.FSTs.recvfrom(bufSize) resp = easyip.Packet(data) # print "in senddpacket, response from Festo", resp if packet.response_errors(resp) is None: self.netlink_ok = True # print "No send Errors" else: self.netlink_ok = False print "errors=%r" % packet.response_errors(resp) else: resp = None return resp def _get_pressure(self): # first arg is the number of requests your making. Leave it as 1 always # Second arg is number of words you are requesting (probably 6, or 16) # third arg is the offset. # words 0-5 are what you sent it. # words 6-9 are not used # words 10-15 are the current values of the presures # packet = easyip.Factory.req_flagword(1, 16, 0) if TESTING: return self.requested_pressures # TEMP for testing # print "attempting to get pressure" try: packet = easyip.Factory.req_flagword(1, 6, 10) resp = self._send_packet(packet) values = resp.decode_payload(easyip.Packet.DIRECTION_REQ) # print list(values) return list(values) except socket.timeout: print "timeout waiting for Pressures from Festo" return [0, 0, 0, 0, 0, 0]
def init_gui(self, master): self.gui = OutputGui() self.gui.init_gui(master, MIN_ACTUATOR_LEN, MAX_ACTUATOR_LEN) self.use_gui = True
class OutputInterface(object): # IS_SERIAL is set True if using serial platform simulator for testing global IS_SERIAL def __init__(self): np.set_printoptions(precision=2, suppress=True) self._calculate_geometry() self.LIMITS = platform_1dof_limits # max movement in a single dof self.platform_disabled_pos = np.empty( 6) # position when platform is disabled self.platform_disabled_pos.fill(DISABLED_LEN) self.platform_winddown_pos = np.empty( 6) # position for attaching stairs self.platform_winddown_pos.fill(WINDDOWN_LEN) self.isEnabled = False # platform disabled if False self.loaded_weight = PLATFORM_UNLOADED_WEIGHT + DEFAULT_PAYLOAD_WEIGHT self.prev_pos = [0, 0, 0, 0, 0, 0] # requested distances stored here self.requested_pressures = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] self.actual_pressures = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] self.prev_time = time.clock() if IS_SERIAL: # configure the serial connection try: self.ser = serial.Serial(port=OutSerialPort, baudrate=57600, timeout=1) print "Out simulator opened on ", OutSerialPort except: print "unable to open Out simulator serial port", OutSerialPort elif not TESTING: self.FSTs = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.FST_addr = (FST_ip, FST_port) if not OLD_FESTO_CONTROLLER: self.FSTs.bind(('0.0.0.0', 0)) self.FSTs.settimeout(1) # timout after 1 second if no response print "" self.prevMsg = [] self.gui = OutputGui() def init_gui(self, master): self.gui.init_gui(master, MIN_ACTUATOR_LEN, MAX_ACTUATOR_LEN) def fin(self): """ free resources used by ths module """ if IS_SERIAL: try: if self.ser and self.ser.isOpen(): self.ser.close() except: pass else: if not TESTING: self.FSTs.close() def get_platform_name(self): return PLATFORM_NAME def get_geometry(self): """ get coordinates of fixed and moving attachment points and mid height """ return base_pos, platform_pos, self.platform_mid_height def get_platform_pos(self): """ get coordinates of fixed platform attachment points """ return platform_pos def get_output_status(self): """ return string describing output status """ if TESTING: return ("Test mode, no output to Festo", "red") if OLD_FESTO_CONTROLLER: return ("Old Festo Controller", "green3") else: if position_request(v == 0 for v in self.actual_pressures): return ("Festo Pressure is Zero", "orange") else: return ("Festo Pressure is Good", "green3" ) # todo, also check if pressure is low def get_platform_mid_height(self): """ get actuater lengths in mid (ready for ride) position """ return self.platform_mid_height # height in mm from base at mid position def get_limits(self): """ provide limit of movement in all 6 DOF from imported platform config file """ return self.LIMITS def set_payload(self, payload_kg): """ set passenger weight in killograms """ self.loaded_weight = PLATFORM_UNLOADED_WEIGHT + payload_kg def set_enable(self, state, actuator_lengths): """ enable platform if True, disable if False actuator_lengths are those needed to achieve current client orientation """ if self.isEnabled != state: self.isEnabled = state print "Platform enabled state is", state if state: self._slow_move(self.platform_disabled_pos, actuator_lengths, 1000) else: self._slow_move(actuator_lengths, self.platform_disabled_pos, 1000) def move_to_limits(self, pos): """ + or - 1 in [x,y,z,ax,ay,az] moves to that limit, 0 to middle Args: pos is list of translations and rotations """ self.moveTo([p * l for p, l in zip(pos, self.limits)]) def swell_for_access(self, interval): """ Briefly raises platform high enough to insert access stairs moves even if disabled Args: interval (int): time in ms before dropping back to start pos """ self._slow_move(self.platform_disabled_pos, self.platform_winddown_pos, 1000) time.sleep(interval) self._slow_move(self.platform_winddown_pos, self.platform_disabled_pos, 1000) def move_platform( self, lengths): # lengths is list of 6 actuator lengths as millimeters """ Move all platform actuators to the given lengths Args: lengths (float): numpy array comprising 6 actuator lengths """ clipped = [] for idx, l in enumerate(lengths): if l < MIN_ACTUATOR_LEN: lengths[idx] = MIN_ACTUATOR_LEN clipped.append(idx) elif l > MAX_ACTUATOR_LEN: lengths[idx] = MAX_ACTUATOR_LEN clipped.append(idx) if len(clipped) > 0: pass # print "Warning, actuators", clipped, "were clipped" if self.isEnabled: if IS_SERIAL: self._move_to_serial(lengths) else: self._move_to(lengths) # only fulfill request if enabled """ else: print "Platform Disabled" """ def show_muscles(self, position_request, muscles): self.gui.show_muscles(position_request, muscles) # private methods def _slow_move(self, start, end, duration): if IS_SERIAL: move_func = self._move_to_serial else: move_func = self._move_to # caution, this moves even if disabled interval = 50 # time between steps in ms steps = duration / interval if steps < 1: self.move(end) else: current = start print "moving from", start, "to", end, "steps", steps delta = [float(e - s) / steps for s, e in zip(start, end)] for step in xrange(steps): current = [x + y for x, y in zip(current, delta)] move_func(copy.copy(current)) self.show_muscles([0, 0, 0, 0, 0, 0], current) time.sleep(interval / 1000.0) def _calculate_geometry(self): # reflect around X axis to generate right side coordinates global base_pos, platform_pos otherSide = copy.deepcopy(base_pos[::-1]) # order reversed for inner in otherSide: inner[1] = -inner[1] # negate Y values base_pos.extend(otherSide) otherSide = copy.deepcopy(platform_pos[::-1]) # order reversed for inner in otherSide: inner[1] = -inner[1] # negate Y values platform_pos.extend(otherSide) base_pos = np.array(base_pos) platform_pos = np.array(platform_pos) # print "\nPlatformOutput using %s configuration" %(PLATFORM_NAME) # print "Actuator lengths: Min %d, Max %d, mid %d" %( MIN_ACTUATOR_LEN, MAX_ACTUATOR_LEN, MID_ACTUATOR_LEN) # use actuator length and the distance between attachment points to calculate height extents a = np.linalg.norm( base_pos[1] - platform_pos[1] ) # distance between consecutive platform attachmment points b = MIN_ACTUATOR_LEN platforMin = math.sqrt( b * b - a * a) # the min vertical movement from center to top or bottom # print "min height", round(platforMin) b = MID_ACTUATOR_LEN self.platform_mid_height = math.sqrt( b * b - a * a) # the mid vertical movement from center to top or bottom # print "mid height", round(self.platform_mid_height) b = MAX_ACTUATOR_LEN platformMax = math.sqrt( b * b - a * a) # the max vertical movement from center to top or bottom # print "max height", round(platformMax) # uncomment this section to plot the array coordinates """ bx= base_pos[:,0] by = base_pos[:,1] plt.scatter(bx,by) px= platform_pos[:,0] py = platform_pos[:,1] plt.axis('equal') plt.scatter(px,py) plt.show() """ # print "base_pos:\n",base_pos # print "platform_pos:\n",platform_pos def _move_to_serial(self, lengths): """ temp hack tpo produce norm output""" # msg = 'jsonrpc:,method":"moveEvent","rawArgs"' + ':'.join([str(self.normalize(item)) for item in lengths]) + ']}' # msg = "rawArgs," + ",".join([str(self.normalize(item)) for item in lengths]) msg = "rawArgs," + ",".join([str(round(item)) for item in lengths]) if msg != self.prevMsg: # print msg self.prevMsg = msg if self.ser.isOpen(): self.ser.write(msg + '\n') # print self.ser.readline() else: print "serial not open" def _move_to(self, lengths): now = time.clock() timeDelta = now - self.prev_time self.prev_time = now load_per_muscle = self.loaded_weight / 6 # if needed we could calculate individual muscle loads pressure = [] for idx, distance in enumerate(lengths): pressure.append( int(1000 * self._convert_MM_to_pressure( idx, distance, timeDelta, load_per_muscle))) self._send(pressure) def _convert_MM_to_pressure(self, idx, distance, timeDelta, load): # global MAX_MUSCLE_LEN, MAX_ACTUATOR_LEN # calculate the percent of muscle contraction to give the desired distance percent = 1 - (distance + MAX_MUSCLE_LEN - MAX_ACTUATOR_LEN) / MAX_MUSCLE_LEN # check for range between 0 and .25 # print "distance =", distance, percent if percent < 0 or percent > 0.25: print "%.2f percent contraction out of bounds for distance %.1f" % ( percent, distance) distDelta = distance - self.prev_pos[ idx] # the change in distance from the previous position accel = (distDelta / 1000) / timeDelta # accleration units are meters per sec if distDelta < 0: force = load * ( 1 - accel ) # TODO here we assume force is same magnitude as expanding muscle ??? # TODO modify formula for force # pressure = 30 * percent*percent + 12 * percent + .01 # assume 25 Newtons for now pressure = 35 * percent * percent + 15 * percent + .03 # assume 25 Newtons for now if PRINT_MUSCLES: print( "muscle %d contracting %.1f mm to %.1f, accel is %.2f, force is %.1fN, pressure is %.2f" % (idx, distDelta, distance, accel, force, pressure)) else: force = load * (1 + accel) # force in newtons not yet used # TODO modify formula for expansion pressure = 35 * percent * percent + 15 * percent + .03 # assume 25 Newtons for now if PRINT_MUSCLES: print( "muscle %d expanding %.1f mm to %.1f, accel is %.2f, force is %.1fN, pressure is %.2f" % (idx, distDelta, distance, accel, force, pressure)) self.prev_pos[idx] = distance # store the distance return pressure def _send(self, muscle_pressures): self.requested_pressures = muscle_pressures # store this for display if reqiured if not TESTING: try: if not OLD_FESTO_CONTROLLER: packet = easyip.Factory.send_flagword(0, muscle_pressures) try: self._send_packet(packet) self.actual_pressures = self._get_pressure() except socket.timeout: print "timeout waiting for replay from", self.FST_addr else: for idx, muscle in enumerate(muscle_pressures): maw = int(muscle * 1000) maw = max(min(6000, muscle), 0) # limit range to 0 to 6000 command = "maw" + str(64 + idx) + "=" + str(maw) # print command, command = command + "\r\n" self.FSTs.sendto(command, self.FST_addr) except: e = sys.exc_info()[0] s = traceback.format_exc() print "error sending to Festo", e, s def _send_packet(self, packet): if not TESTING: data = packet.pack() self.FSTs.sendto(data, self.FST_addr) # print "sending to", self.FST_addr print "in sendpacket,waiting for response..." data, srvaddr = self.FSTs.recvfrom(bufSize) resp = easyip.Packet(data) print "in senddpacket, response from Festo", resp if packet.response_errors(resp) is None: print "No send Errors" else: print "errors=%r" % packet.response_errors(resp) return resp def _get_pressure(self): # fist arg is the number of requests your making. Leave it as 1 always # Second arg is number of words you are requesting (probably 6, or 16) # third arg is the offset. # words 0-5 are what you sent it. # words 6-9 are not used # words 10-15 are the current values of the presures # packet = easyip.Factory.req_flagword(1, 16, 0) if TESTING: return self.requested_pressures # TEMP for testing print "attempting to get pressure" try: packet = easyip.Factory.req_flagword(1, 6, 10) resp = self._send_packet(packet) values = resp.decode_payload(easyip.Packet.DIRECTION_REQ) return list(values) except timeout: print "timeout waiting for Pressures from Festo at", self.addr return None