def __init__(self, record_training_data=False, model=None): print('Setting up PiCar...') if record_training_data and not model: self.record_training_data = True print('Recording training data...') else: self.record_training_data = False if model: self.model_manager = ModelManager() self.model_manager.load_model(model) else: self.model_manager = None self.dc = DriveController() self.aws_manager = AWSManager() self.setup_camera() # Structs for collecting training images and labels self.training_images = [] self.training_labels = [] # Stores the current user drive instruction self.current_drive_input = 'forward' # Using pygame in process remote keyboard inputs pygame.init() pygame.display.set_mode((100, 100))
def start_listener(pod_data, sql_wrapper): server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind(('127.0.0.1', 6666)) server_socket.listen(5) (client_socket, address) = server_socket.accept() while True: chunk = client_socket.recv(5) if chunk == "KILL\n": try: # stop the pod client_socket.send("KILLED\n") dc = DriveController() dc.send_kill_pod() logging.info("Pod kill power sent") break except socket.error, e: logging.debug("Socket error: " + str(e)) client_socket.close() sql_wrapper.execute( """INSERT INTO states VALUES (NULL,%s,%s)""", (datetime.datetime.now().strftime( constants.TIME_FORMAT), "FAULT STATE")) pod_data.state = constants.STATE_FAULT
def __init__(self, sensor_polling=5): self.robot = Robot() self.current_task = Tasks.NONE self.queued_task = Tasks.INITIAL_SCAN # Setup radio for communication with external controller self.radio = Radio( self.robot.getDevice("emitter"), self.robot.getDevice("receiver"), sampling_rate=sensor_polling ) # Setup all positioning sensors self.positioning_system = PositioningSystem( self.robot.getDevice("turret_motor"), self.robot.getDevice("gps"), self.robot.getDevice("compass"), RealUltrasonic(self.robot, "distance_sensor_front", 21), RealUltrasonic(self.robot, "distance_sensor_rear", 21), sampling_rate=sensor_polling ) # Setup the pincer self.pincer_controller = PincerController( self.robot.getDevice("pincer_motor_1"), self.robot.getDevice("pincer_motor_2") ) # Setup drive controller for navigation self.drive_controller = DriveController( self.robot.getDevice("drive_motor_1"), self.robot.getDevice("drive_motor_2") ) self.scanning_controller = ServoArmController() # Setup color sensor self.color_sensor = ColorSensor( self.robot.getDevice("light_sensor"), sampling_rate=sensor_polling ) self.IR_sensor = PassiveIR(self.robot.getDevice("IR sensor"), sensor_polling) # Start with the pincer fully open self.pincer_controller.open_pincer() self.requested_target = None self.locked_target = None # These algorithms are created/ destroyed as needed self.block_searching_algorithm = None self.reversing_algorithm = None self.depositing_algorithm = None
def __init__(self, sensor_polling=5): self.robot = Robot() self.current_task = Tasks.NONE self.queued_task = Tasks.STATIONARY_SCAN self.robot_color = "green" # Setup radio for communication with external controller self.radio = Radio(self.robot.getDevice("emitter"), self.robot.getDevice("receiver"), sampling_rate=sensor_polling) # Setup all positioning sensors self.positioning_system = PositioningSystem( self.robot.getDevice("turret_motor"), self.robot.getDevice("gps"), self.robot.getDevice("compass"), RealUltrasonic(self.robot, "distance_sensor_front", 21), RealUltrasonic(self.robot, "distance_sensor_rear", 21), sampling_rate=sensor_polling) # Setup the pincer self.pincer_controller = PincerController( self.robot.getDevice("pincer_motor_1"), self.robot.getDevice("pincer_motor_2")) # Setup drive controller for navigation self.drive_controller = DriveController( self.robot.getDevice("drive_motor_1"), self.robot.getDevice("drive_motor_2")) self.scanning_controller = ServoArmController() # Enable light sensor self.light = self.robot.getDevice("light_sensor") self.light.enable(sensor_polling) self.IR_sensor = IRSensor(self.robot.getDevice("IR sensor"), sensor_polling) # Start with the pincer fully open self.pincer_controller.open_pincer() self.queued_waypoints = []
class RobotController: def __init__(self, sensor_polling=5): self.robot = Robot() self.current_task = Tasks.NONE self.queued_task = Tasks.INITIAL_SCAN # Setup radio for communication with external controller self.radio = Radio( self.robot.getDevice("emitter"), self.robot.getDevice("receiver"), sampling_rate=sensor_polling ) # Setup all positioning sensors self.positioning_system = PositioningSystem( self.robot.getDevice("turret_motor"), self.robot.getDevice("gps"), self.robot.getDevice("compass"), RealUltrasonic(self.robot, "distance_sensor_front", 21), RealUltrasonic(self.robot, "distance_sensor_rear", 21), sampling_rate=sensor_polling ) # Setup the pincer self.pincer_controller = PincerController( self.robot.getDevice("pincer_motor_1"), self.robot.getDevice("pincer_motor_2") ) # Setup drive controller for navigation self.drive_controller = DriveController( self.robot.getDevice("drive_motor_1"), self.robot.getDevice("drive_motor_2") ) self.scanning_controller = ServoArmController() # Setup color sensor self.color_sensor = ColorSensor( self.robot.getDevice("light_sensor"), sampling_rate=sensor_polling ) self.IR_sensor = PassiveIR(self.robot.getDevice("IR sensor"), sensor_polling) # Start with the pincer fully open self.pincer_controller.open_pincer() self.requested_target = None self.locked_target = None # These algorithms are created/ destroyed as needed self.block_searching_algorithm = None self.reversing_algorithm = None self.depositing_algorithm = None def send_new_scan(self): message = protocol.ScanDistanceReading( self.robot.getName(), self.positioning_system.get_2D_position(), self.positioning_system.get_world_bearing(), self.positioning_system.get_turret_angle(), self.positioning_system.get_distance_readings(), self.pincer_controller.is_closed, ) self.radio.send_message(message) def process_message(self, message): """ Take action on the received message. """ if isinstance(message, protocol.KillImmediately): util.log_msg(util.Logging.INFO, f"Killed robot {self.robot.getName()}") self.queued_task = Tasks.DEAD elif isinstance(message, protocol.GiveRobotTarget): self.requested_target = message.target # Wake the robot if its not doing anything if self.current_task == Tasks.NONE: self.queued_task = Tasks.FOLLOWING_CONTROLLER elif isinstance(message, protocol.AskRobotSearch): self.requested_target = message.target # Ensure robot isn't already searching if self.current_task == Tasks.NONE or self.current_task == Tasks.FOLLOWING_CONTROLLER: self.queued_task = Tasks.FACE_TARGET_SEARCH elif isinstance(message, protocol.AskRobotDeposit): # Robot should only attempt to deposit block if all other actions are finished if self.current_task == Tasks.NONE or self.current_task == Tasks.FOLLOWING_CONTROLLER: self.queued_task = Tasks.DEPOSITING_BLOCK else: raise NotImplementedError(f"Could not process message {message}") def process_controller_instructions(self): """ Receive and process all instructions on the current channel. """ for message in self.radio.get_messages(): # Ensure this is robot the correct recipient if message.robot_name == self.robot.getName(): self.process_message(message) def __clean_current_task(self, about_to_end, about_to_start): """ Runs when the current robot task is about to end. Note: 'self.current_task' is about_to_end 'self.queued_task' is about_to_start DO NOT MODIFY THESE VARIABLES HERE """ if about_to_end == Tasks.SEARCHING_BLOCK: self.block_searching_algorithm.clean() self.block_searching_algorithm = None if about_to_end == Tasks.REVERSING or about_to_end == Tasks.REVERSING_LONG: self.reversing_algorithm = None if about_to_end == Tasks.DEPOSITING_BLOCK: # Report the exact dropoff position self.radio.send_message(protocol.ReportBlockDropoff( self.robot.getName(), self.positioning_system.get_pincer_position() )) self.depositing_algorithm = None if about_to_end == Tasks.FACE_TARGET_SEARCH: self.locked_target = None def __initialize_queued_task(self, about_to_end, about_to_start): """ Runs when the next robot task is about to start. Note: 'self.current_task' is about_to_end 'self.queued_task' is about_to_start DO NOT MODIFY THESE VARIABLES HERE """ util.log_msg(util.Logging.INFO, f"{self.robot.getName()} starting new task: {about_to_start}") if about_to_start == Tasks.INITIAL_SCAN: self.drive_controller.halt() if about_to_start == Tasks.FULL_SCAN: self.scanning_controller.clockwise = True if about_to_start == Tasks.DEAD: self.drive_controller.halt() self.positioning_system.kill_turret() if about_to_start == Tasks.SEARCHING_BLOCK: util.log_msg(util.Logging.INFO, "Started searching for block") self.block_searching_algorithm = BlockSearch( self.IR_sensor, self.positioning_system, self.drive_controller, self.pincer_controller ) if about_to_start == Tasks.REVERSING: self.reversing_algorithm = Reversing( self.drive_controller, 200 # Reverse for 10 ticks to ensure robot doesn't collide with hidden blocks ) if about_to_start == Tasks.REVERSING_LONG: self.reversing_algorithm = Reversing( self.drive_controller, 300 # Reverse for 10 ticks to ensure robot doesn't collide with hidden blocks ) if about_to_start == Tasks.DEPOSITING_BLOCK: self.depositing_algorithm = BlockDeposit( self.robot.getName(), self.positioning_system, self.drive_controller, self.pincer_controller ) def switch_to_queued_task(self): """ Robot will switch to the queued task after completing the necessary initialization and cleanup. """ if self.current_task == self.queued_task: return # nothing to do self.__initialize_queued_task(self.current_task, self.queued_task) self.__clean_current_task(self.current_task, self.queued_task) self.current_task = self.queued_task def tick(self): # A dead robot can never be revived, don't even try to do anything if self.current_task == Tasks.DEAD: return # Get the lastest information from controller self.process_controller_instructions() # Update the controller self.send_new_scan() # Ensure IR readings are up-to-date self.IR_sensor.get_distance() # Execute the current task if self.current_task == Tasks.FOLLOWING_CONTROLLER: # Ensure robot knows where to go. If not, wait for instructions if self.requested_target is None: self.queued_task = Tasks.NONE # Wait for further instructions self.drive_controller.navigate_toward_point(self.positioning_system, self.requested_target) # Also scan while driving self.scanning_controller.driving_scan(self.positioning_system) # if not self.pincer_controller.is_closed and self.IR_sensor.get_distance() < BlockSearch.MAX_BLOCK_DIST: # self.queued_task = Tasks.SEARCHING_BLOCK elif self.current_task == Tasks.INITIAL_SCAN: if self.scanning_controller.stationary_scan(self.positioning_system): # Only blank the robot controller if nothing is planned self.queued_task = Tasks.NONE elif self.current_task == Tasks.FULL_SCAN: if self.scanning_controller.active_scan(self.positioning_system): # Only blank the robot controller if nothing is planned self.queued_task = Tasks.NONE elif self.current_task == Tasks.NONE: # Scan to update map self.scanning_controller.stationary_scan(self.positioning_system) elif self.current_task == Tasks.SEARCHING_BLOCK: # Scan to (attempt) avoid false positives self.scanning_controller.driving_scan(self.positioning_system) # Algorithm returns code upon completion result = self.block_searching_algorithm() if result == BlockSearch.FOUND_BLOCK: self.queued_task = Tasks.SCANNING_COLOR elif result != BlockSearch.IN_PROGRESS: # Report this search has failed self.radio.send_message(protocol.IRReportFailed( self.robot.getName(), self.positioning_system.block_detection_position() )) if result == BlockSearch.TIMEOUT: # Robot has moved forwards, avoid unintended collisions self.queued_task = Tasks.REVERSING elif result == BlockSearch.FAILED: # Robot is probably in a safe position to scan self.queued_task = Tasks.FULL_SCAN else: raise NotImplementedError() elif self.current_task == Tasks.SCANNING_COLOR: self.drive_controller.halt() block_color = self.color_sensor.scan_color() color_name = util.get_robot_color_string(block_color) # Log this color to the console for point util.log_msg(util.Logging.INFO, f"Robot '{self.robot.getName()}' Found {color_name} block") # Alert the controller of the true block color self.radio.send_message(protocol.ReportBlockColor( self.robot.getName(), self.positioning_system.get_2D_position(), block_color )) if block_color == self.robot.getName(): # Block is correct color and pincer is already closed self.queued_task = Tasks.REVERSING else: # Block color is wrong, open pincer to reject block self.queued_task = Tasks.REJECT_BLOCK elif self.current_task == Tasks.REJECT_BLOCK: # Algorithm returns True upon completion if self.pincer_controller.open_pincer(): self.queued_task = Tasks.REVERSING elif self.current_task == Tasks.FACE_TARGET_SEARCH: # Algorithm returns True upon completion is_finished = self.drive_controller.turn_toward_point( self.positioning_system, self.requested_target ) if is_finished: self.queued_task = Tasks.SEARCHING_BLOCK elif self.current_task == Tasks.REVERSING or self.current_task == Tasks.REVERSING_LONG: # Algorithm returns True upon completion if self.reversing_algorithm(): self.queued_task = Tasks.FULL_SCAN elif self.current_task == Tasks.DEPOSITING_BLOCK: # Algorithm returns True upon completion if self.depositing_algorithm(): util.log_msg(util.Logging.INFO, "Block deposited") self.queued_task = Tasks.REVERSING_LONG else: util.log_msg(util.Logging.ERROR, f"Unimplemented task type: {self.current_task}") raise NotImplementedError() # Tick finished, switch tasks if necessary self.switch_to_queued_task()
class PiCar: # Camera Info SCREEN_WIDTH = 200 SCREEN_HEIGHT = 66 FRAME_RATE = 24 def __init__(self, record_training_data=False, model=None): print('Setting up PiCar...') if record_training_data and not model: self.record_training_data = True print('Recording training data...') else: self.record_training_data = False if model: self.model_manager = ModelManager() self.model_manager.load_model(model) else: self.model_manager = None self.dc = DriveController() self.aws_manager = AWSManager() self.setup_camera() # Structs for collecting training images and labels self.training_images = [] self.training_labels = [] # Stores the current user drive instruction self.current_drive_input = 'forward' # Using pygame in process remote keyboard inputs pygame.init() pygame.display.set_mode((100, 100)) def setup_camera(self): print('Initializing camera...') self.camera = PiCamera() self.camera.resolution = (self.SCREEN_WIDTH, self.SCREEN_HEIGHT) self.camera.framerate = self.FRAME_RATE self.raw_capture = PiRGBArray(self.camera, size=(self.SCREEN_WIDTH, self.SCREEN_HEIGHT)) # allow the camera to warm up time.sleep(1) print('Camera initialization complete...') def process_user_inputs(self): for event in pygame.event.get(): if event.type == pygame.KEYUP: self.dc.forward() self.current_drive_input = 'forward' elif event.type == pygame.KEYDOWN: if event.key == pygame.K_RIGHT: self.dc.pivot_right() self.current_drive_input = 'right' elif event.key == pygame.K_LEFT: self.dc.pivot_left() self.current_drive_input = 'left' else: self.dc.forward() self.current_drive_input = 'forward' def convert_model_output_to_drive_command(self, model_output): print(str(model_output)) max_index = np.argmax(model_output) if max_index == 0: self.dc.forward() self.current_drive_input = 'forward' elif max_index == 1: self.dc.pivot_right() self.current_drive_input = 'right' elif max_index == 2: self.dc.pivot_left() self.current_drive_input = 'left' print(self.current_drive_input) def drive(self): for frame in self.camera.capture_continuous(self.raw_capture, format="bgr", use_video_port=True): image = frame.array if self.model_manager: # Use model to steer PiCar image = image / 255.0 output = self.model_manager.run_inference(image) self.convert_model_output_to_drive_command(output) else: # Use remote keyboard inputs to steer PiCar self.process_user_inputs() # Record training data if self.record_training_data: self.training_images.append(image) self.training_labels.append(self.current_drive_input) # Display camera feed cv2.imshow("Feed", image) key = cv2.waitKey(1) & 0xFF self.raw_capture.truncate(0) # Exit program if user pressed 'q' if key == ord("q"): self.dc.stop() # Upload training data to AWS before exiting if self.record_training_data: self.aws_manager.upload_training_data(self.training_images, self.training_labels) break
class RobotController: def __init__(self, sensor_polling=5): self.robot = Robot() self.current_task = Tasks.NONE self.queued_task = Tasks.STATIONARY_SCAN self.robot_color = "green" # Setup radio for communication with external controller self.radio = Radio(self.robot.getDevice("emitter"), self.robot.getDevice("receiver"), sampling_rate=sensor_polling) # Setup all positioning sensors self.positioning_system = PositioningSystem( self.robot.getDevice("turret_motor"), self.robot.getDevice("gps"), self.robot.getDevice("compass"), RealUltrasonic(self.robot, "distance_sensor_front", 21), RealUltrasonic(self.robot, "distance_sensor_rear", 21), sampling_rate=sensor_polling) # Setup the pincer self.pincer_controller = PincerController( self.robot.getDevice("pincer_motor_1"), self.robot.getDevice("pincer_motor_2")) # Setup drive controller for navigation self.drive_controller = DriveController( self.robot.getDevice("drive_motor_1"), self.robot.getDevice("drive_motor_2")) self.scanning_controller = ServoArmController() # Enable light sensor self.light = self.robot.getDevice("light_sensor") self.light.enable(sensor_polling) self.IR_sensor = IRSensor(self.robot.getDevice("IR sensor"), sensor_polling) # Start with the pincer fully open self.pincer_controller.open_pincer() self.queued_waypoints = [] def send_new_scan(self): message = protocol.ScanDistanceReading( self.robot.getName(), self.positioning_system.get_2D_position(), self.positioning_system.get_world_bearing(), self.positioning_system.get_turret_angle(), self.positioning_system.get_distance_readings()) self.radio.send_message(message) def process_message(self, message): """ Take action on the received message. """ if isinstance(message, protocol.WaypointList): self.queued_waypoints.append(message.waypoints) elif isinstance(message, protocol.KillImmediately): self.queued_task = Tasks.NONE elif isinstance(message, protocol.RemoveWaypoints): self.drive_controller.set_waypoints([]) self.queued_waypoints = [] self.queued_task = Tasks.SWITCH_BLOCK_TARGET else: raise NotImplementedError() def process_controller_instructions(self): """ Receive and process all instructions on the current channel. """ for message in self.radio.get_messages(): # Ensure this is robot the correct recipient if message.robot_name == self.robot.getName(): self.process_message(message) def __clean_current_task(self, about_to_end, about_to_start): """ Runs when the current robot task is about to end. Note: 'self.current_task' is about_to_end 'self.queued_task' is about_to_start DO NOT MODIFY THESE VARIABLES HERE """ if about_to_end == Tasks.NAVIGATE_TO_WAYPOINT: self.drive_controller.halt() if about_to_end == Tasks.BLOCK_COLLECTION: self.block_collection_controller = None self.drive_controller.halt() if about_to_end == Tasks.BLOCK_COLLECTION: self.pincer_controller.open_pincer() def __initialize_queued_task(self, about_to_end, about_to_start): """ Runs when the next robot task is about to start. Note: 'self.current_task' is about_to_end 'self.queued_task' is about_to_start DO NOT MODIFY THESE VARIABLES HERE """ if about_to_start == Tasks.STATIONARY_SCAN: self.drive_controller.halt() if about_to_start == Tasks.GRAB_BLOCK: self.pincer_controller.close_pincer() if about_to_start == Tasks.SWITCH_BLOCK_TARGET: self.pincer_controller.open_pincer() if about_to_start == Tasks.BLOCK_COLLECTION: self.block_collection_controller = BlockCollection( self.robot.getName(), self.drive_controller, self.positioning_system, self.pincer_controller, self.light, self.radio, self.IR_sensor) def switch_to_queued_task(self): """ Robot will switch to the queued task after completing the necessary initialization and cleanup. """ if self.current_task == self.queued_task: return # nothing to do self.__initialize_queued_task(self.current_task, self.queued_task) self.__clean_current_task(self.current_task, self.queued_task) self.current_task = self.queued_task def process_queued_waypoints(self): if len(self.queued_waypoints ) == 0 or self.drive_controller.has_waypoints(): return next_waypoints = self.queued_waypoints.pop(0) if self.current_task == Tasks.BLOCK_COLLECTION: self.drive_controller.set_waypoints(next_waypoints[:-1]) self.block_collection_controller.set_block_pos(next_waypoints[-1]) elif self.current_task == Tasks.NAVIGATE_TO_WAYPOINT: self.drive_controller.set_waypoints(next_waypoints) def tick(self): # Get the lastest information from controller self.process_controller_instructions() # Check if any received waypoints can be loaded safely into navigate_waypoints self.process_queued_waypoints() # Update the controller self.send_new_scan() # Execute the current task if self.current_task == Tasks.NAVIGATE_TO_WAYPOINT: if self.drive_controller.navigate_waypoints( self.positioning_system, reverse=True): # Reached final waypoint! Change to grabbing state self.queued_task = Tasks.BLOCK_COLLECTION elif self.current_task == Tasks.STATIONARY_SCAN: if self.scanning_controller.stationary_scan( self.positioning_system): self.queued_task = Tasks.BLOCK_COLLECTION elif self.current_task == Tasks.BLOCK_COLLECTION: result = self.block_collection_controller() if result == BlockCollection.IN_PROGRESS: pass elif result == BlockCollection.BLOCK_IGNORED: self.queued_task = Tasks.SWITCH_BLOCK_TARGET else: raise NotImplementedError() elif self.current_task == Tasks.SWITCH_BLOCK_TARGET: # Immediately switch the task back to block collection self.queued_task = Tasks.BLOCK_COLLECTION elif self.current_task == Tasks.NONE: pass # TODO: maybe query controller here else: print("[ERROR] Unimplemented task type: ", self.current_task) raise NotImplementedError() # Demonstrate the mapping for moving turret if self.current_task != Tasks.STATIONARY_SCAN: self.scanning_controller.driving_scan(self.positioning_system) # Tick finished, switch tasks if necessary self.switch_to_queued_task()
#!/usr/bin/python # # FishPi - An autonomous drop in the ocean # # Calibrate ESC through PWM controller # import raspberrypi from time import sleep from drive_controller import DriveController if __name__ == "__main__": print "Calibrating ESC" drive = DriveController(debug=True, i2c_bus=raspberrypi.i2c_bus()) raw_input("Power on ESC and enter calibration mode... Then press <ENTER>...") print "run full ahead for 5 sec..." drive.set_throttle(1.0) sleep(5) print "returning to neutral for 5 sec" drive.set_throttle(0.0) sleep(5) print "run full reverse for 5 sec" drive.set_throttle(-1.0) sleep(5)
from reporters.spacex_udp_sender import spacex_udp_sender def enter_fault_state(): states.fault_state.start(pod_data, sql_wrapper) # Give it time to send fault state to spacex and abort time.sleep(10) sys.exit(1) logging.basicConfig(filename='test.log', level=logging.DEBUG) logging.getLogger().addHandler(logging.StreamHandler()) pod_data = PodData() sql_wrapper = MySQLWrapper(logging) thread.start_new_thread(spacex_udp_sender, (pod_data, logging)) drive_controller = DriveController() inited_tty = None suspension_tcp_socket = None try: inited_tty, suspension_tcp_socket = states.initialization_state.start( pod_data, sql_wrapper, drive_controller) except MySQLdb.OperationalError, e: logging.error( "Initialization state failed because of mysql operational error: " + str(e) + ". Aborting run...") enter_fault_state() except RuntimeError, e: logging.error(e) enter_fault_state()