class NLMaster: """Natural language master server.""" def __init__(self, text_port, map_port): self.text_port = text_port self.map_port = map_port self.ipad_conn = None self.comm_proxy = None self.map_proxy = None self.state_mgr = None def run(self, aut_path=None): """Intialize all NL components.""" # pylint: disable=W0603 global WORLD_KNOWLEDGE # Start the NL pipeline if not aut_path: print "Starting NL pipeline..." init_pipes() else: print "Skipping loading nlpipeline because an automaton was loaded" # Start the ROS node print "Initializing ROS node..." rospy.init_node('nlproxy') # Set up the state mgr and its callbacks print "Starting state manager..." self.state_mgr = StateManager(self) self.state_mgr.set_basedir(LTLGEN_BASE_DIR) # Load the automaton if needed if aut_path: self.state_mgr.load_test_automaton(aut_path, False) # Create world knowledge print "Starting knowledge..." WORLD_KNOWLEDGE = Knowledge.Knowledge(self) self.state_mgr.world_knowledge = WORLD_KNOWLEDGE # Wait a little for ROS to avoid timing startup issues. print "Waiting for ROS node to settle..." time.sleep(1) # Set up ROS listening print "Subscribing to notifications..." # Set up state manager's sending and listening pub = add_ltl_publisher() self.state_mgr.set_publisher(pub) add_subscriber(LTL_ENVIRONMENT_TOPIC, self.state_mgr.process_sensor_data) add_subscriber(LTL_ENVIRONMENT_TOPIC, WORLD_KNOWLEDGE.process_sensor_data) # Create the input comm_proxy and iPad connections print "Starting comm_proxy..." self.comm_proxy = CallbackSocket(self.text_port) self.comm_proxy.register_callback(self.process_text) self.ipad_conn = iPadConnection(self.map_port) self.ipad_conn.register_rename_callback(Knowledge.rename_entity) self.ipad_conn.register_text_callback(self.process_text) # TODO Add highlight callback self.map_proxy = MapProxy(self.ipad_conn) add_subscriber(LTL_ENVIRONMENT_TOPIC, self.ipad_conn.add_icons) WORLD_KNOWLEDGE.map_proxy = self.map_proxy # Set up odometry forwarding to the ipad tf = TransformListener() while not tf.frameExists("/map"): rospy.logwarn("Not ready for transforms yet") rospy.sleep(1.0) position_proxy = RobotPositionProxy(self.ipad_conn,tf) rospy.Subscriber(ODOM_TOPIC, Odometry, position_proxy.forward_position) # Set up getting directions direction_proxy = DirectionProxy() rospy.Subscriber(LOCATION_TOPIC, String, direction_proxy.set_location) WORLD_KNOWLEDGE.direction_proxy = direction_proxy print "NLMaster startup complete!" print "*" * 80 # Finally, wait for input before quitting try: while True: text = raw_input("").strip() if text == "q": break except (KeyboardInterrupt, EOFError): pass except: raise finally: # Only shutdown the pipeline if we actually were taking language input if not aut_path: print "Shutting down NL pipeline..." close_pipes() self.comm_proxy.shutdown() self.ipad_conn.shutdown() sys.exit() def process_text(self, text): """Parse text and pass it to semantics.""" if text: # Clean unicode first if needed if isinstance(text, unicode): text = text.encode('ascii', 'ignore') print "Parsing:", repr(text) parse = parse_text(text) result = WORLD_KNOWLEDGE.process_parse_tree(parse, text) answer = result[0] new_commands = result[3] # Use the answer if there was one and it was a string response = answer if answer and isinstance(answer, str) else "" # Also, echo back any new commands command_echo = make_response(new_commands) # Combine the responses as needed. if not response: response = command_echo elif new_commands: response += " " + command_echo if response: self.send_response(response) print "Completed:", repr(text) def send_response(self, text): """Send text to all listeners.""" print "Sending text to listeners:", repr(text) self.ipad_conn.sendtext(text) self.comm_proxy.send(text)
def test_fixed(aut_path): """Test the state manager on a fixed automaton.""" smgr = StateManager() smgr.set_publisher(FakePublisher) smgr.load_test_automaton(aut_path, True) test_smgr(smgr)