def get_robot_roi(self):
        """Find the roi of the robot at it's waypoint - in case no target ROI is passed
        Make sure the randomly generated viewpoints are all in this roi also - i.e. this room
        """
        self.robot_polygon = None
        # for (roi, meta) in self.soma_roi_store.query(SOMAROIObject._type):  # OLD SOMA
        query = SOMAQueryROIsRequest(query_type=0,
                                     roiconfigs=[self.soma_config],
                                     returnmostrecent=True)
        for roi in self.soma_query(query).rois:
            if roi.map_name != self.soma_map: continue
            if roi.config != self.soma_config: continue
            #if roi.geotype != "Polygon": continue
            polygon = Polygon([(p.position.x, p.position.y)
                               for p in roi.posearray.poses])

            if polygon.contains(
                    Point([
                        self.robot_pose.position.x, self.robot_pose.position.y
                    ])):
                rospy.loginfo("Robot (%s,%s) in ROI: %s" %
                              (self.robot_pose.position.x,
                               self.robot_pose.position.y, roi.type))
                self.robot_polygon = polygon
                return True
        rospy.logwarn("This waypoint is not defined in a ROI")
        return False
示例#2
0
class MapBuilder():
    def __init__(self):
        rospy.init_node("map_builder")

        self.map_building_service = rospy.Service(
            rospy.get_param("~service_building_map_area"), BuildingMapArea,
            self.handle_building_map_area)
        rospy.loginfo(
            "{class_name} : service building map area connected".format(
                class_name=self.__class__.__name__))

        self.map_saving_service = rospy.Service(
            rospy.get_param("~service_saving_map_area"), SavingMapArea,
            self.handle_saving_map_area)
        rospy.loginfo(
            "{class_name} : service saving map area connected".format(
                class_name=self.__class__.__name__))

        self.server = InteractiveMarkerServer("simple_marker")

        self.coord_IMs = {}
        self.current_dir = os.path.dirname(os.path.realpath(__file__))
        self.load_last_map()
        self.current_area_service = rospy.Service(
            rospy.get_param("~service_get_current_area_name"), CurrentArea,
            self.handle_current_area_service)
        rospy.loginfo(
            "{class_name} : service get current map area connected".format(
                class_name=self.__class__.__name__))

        rospy.loginfo("{class_name} : Init completed".format(
            class_name=self.__class__.__name__))

    def handle_current_area_service(self, req):
        """
        Will handle the get_current_map_area service call. This function will get the XY coordinates of a point in parameter and determine in which room this point is located.
        Returns a response containing the room name.

        :param req: input parameters of the service
        :type action: CurrentArea
    
        """
        x_robot = req.coord_x
        y_robot = req.coord_y
        point_to_check = Point(x_robot, y_robot)

        for room in self.coord_IMs.keys():
            list_points = []
            for i in range(0, len(self.coord_IMs[room].keys())):
                list_points.append((self.coord_IMs[room][str(i)]['x'],
                                    self.coord_IMs[room][str(i)]['y']))

            self.polygon_room = Polygon(list_points)
            validation = self.polygon_room.contains(point_to_check)
            if validation == True:
                return CurrentAreaResponse(room)

        return CurrentAreaResponse('')

    def load_last_map(self):
        """
        Will load the file specified in config file containing the map rooms. Displays the interactive markers on the last saved points
        """
        rospy.loginfo(self.current_dir)
        file_path = os.path.join(self.current_dir,
                                 rospy.get_param("~map_file_path"))

        try:
            with open(file_path, 'r+') as json_file:
                data = json.load(json_file)

            self.coord_IMs = data

            for room in data.keys():
                for point_id in data[str(room)].keys():
                    int_marker = InteractiveMarker()
                    int_marker.header.frame_id = "/map"
                    int_marker.name = "marker_" + room + "_" + point_id
                    int_marker.description = "marker_" + room + "_" + point_id

                    int_marker.pose.position.x = data[str(room)][point_id]['x']
                    int_marker.pose.position.y = data[str(room)][point_id]['y']
                    # create a grey box marker
                    box_marker = Marker()
                    box_marker.header.frame_id = "map"
                    box_marker.type = Marker.CUBE
                    box_marker.pose.position.x = data[str(room)][point_id]['x']
                    box_marker.pose.position.y = data[str(room)][point_id]['y']
                    box_marker.scale.x = 0.2
                    box_marker.scale.y = 0.2
                    box_marker.scale.z = 0.2
                    box_marker.color.r = 0.0
                    box_marker.color.g = 0.5
                    box_marker.color.b = 0.5
                    box_marker.color.a = 1.0

                    # create a non-interactive control which contains the box
                    box_control = InteractiveMarkerControl()
                    box_control.always_visible = True
                    box_control.markers.append(box_marker)

                    # add the control to the interactive marker
                    int_marker.controls.append(box_control)

                    # create a control which will move the box
                    # this control does not contain any markers,
                    # which will cause RViz to insert two arrows

                    rotate_control = InteractiveMarkerControl()
                    rotate_control.orientation.w = 1
                    rotate_control.orientation.x = 1
                    rotate_control.orientation.y = 0
                    rotate_control.orientation.z = 0
                    rotate_control.name = "move_x"
                    rotate_control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS

                    # # add the control to the interactive marker
                    int_marker.controls.append(rotate_control)

                    rotate_control = InteractiveMarkerControl()
                    rotate_control.orientation.w = 1
                    rotate_control.orientation.x = 0
                    rotate_control.orientation.y = 0
                    rotate_control.orientation.z = 1
                    rotate_control.name = "move_y"
                    rotate_control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS
                    int_marker.controls.append(rotate_control)
                    # add the interactive marker to our collection &
                    # tell the server to call processFeedback() when feedback arrives for it
                    self.server.insert(int_marker, self.processFeedback)

                    self.server.applyChanges()

            rospy.loginfo("{class_name} : Map loaded".format(
                class_name=self.__class__.__name__))
        except:
            rospy.logwarn("{class_name} : No map could be loaded".format(
                class_name=self.__class__.__name__))

    def handle_saving_map_area(self, req):
        """
        Will handle the saving_map_area service call. This function will save the coordinates of each interactive marker in a JSON.
        Returns a text message as response

        :param req: input parameters of the service
        :type action: SavingMapArea
        """

        file_path = os.path.join(self.current_dir,
                                 rospy.get_param("~map_file_path"))

        try:
            with open(file_path, 'r+') as json_file:
                data = json.load(json_file)
        except:
            data = {}

        if data == {}:
            with open(file_path, 'w+') as json_file:
                json.dump(self.coord_IMs, json_file, indent=4)
                json_file.truncate()

        else:
            for key in self.coord_IMs.keys():
                for id in self.coord_IMs[key].keys():
                    if key in data.keys():
                        data[key][id] = self.coord_IMs[key][id]
                    else:
                        data[key] = {}
                        data[key][id] = self.coord_IMs[key][id]

            with open(file_path, 'w+') as json_file:
                json.dump(data, json_file, indent=4)
                json_file.truncate()

        return SavingMapAreaResponse('OK')

    def processFeedback(self, feedback):
        """
        Will display the coordinates of the interactive marker which has just been moved.
        :param feedback: feedback of the interactive marker server
        :type feedback: InteractiveMarkerFeedback
        """
        p = feedback.pose.position
        rospy.loginfo("{class_name} : ".format(
            class_name=self.__class__.__name__) + feedback.marker_name +
                      " is now at " + str(p.x) + ", " + str(p.y) + ", " +
                      str(p.z))

        room = feedback.marker_name.split("_")[1]

        self.coord_IMs[room][feedback.marker_name.split("_")[-1]] = {
            "x": p.x,
            "y": p.y
        }
        rospy.loginfo("-------")

        rospy.loginfo(self.coord_IMs)
        rospy.loginfo("-------")

    def handle_building_map_area(self, req):
        """
        Will handle the building_map_area service call. This function will create the interactive markers to build a new room.
        Returns a text message as response

        :param req: input parameters of the service
        :type action: BuildingMapArea
        """

        area_name = req.area_name
        interactive_markers_number = req.interactive_markers_number
        self.coord_IMs[area_name] = {}

        for i in range(0, interactive_markers_number):
            int_marker = InteractiveMarker()
            int_marker.header.frame_id = "/map"
            int_marker.name = "marker_" + area_name + "_" + str(i)
            int_marker.description = "marker_" + area_name + "_" + str(i)

            # create a grey box marker
            box_marker = Marker()
            box_marker.type = Marker.CUBE
            box_marker.scale.x = 0.2
            box_marker.scale.y = 0.2
            box_marker.scale.z = 0.2
            box_marker.color.r = 0.0
            box_marker.color.g = 0.5
            box_marker.color.b = 0.5
            box_marker.color.a = 1.0

            # create a non-interactive control which contains the box
            box_control = InteractiveMarkerControl()
            box_control.always_visible = True
            box_control.markers.append(box_marker)

            # add the control to the interactive marker
            int_marker.controls.append(box_control)

            # create a control which will move the box
            # this control does not contain any markers,
            # which will cause RViz to insert two arrows

            rotate_control = InteractiveMarkerControl()
            rotate_control.orientation.w = 1
            rotate_control.orientation.x = 1
            rotate_control.orientation.y = 0
            rotate_control.orientation.z = 0
            rotate_control.name = "move_x"
            rotate_control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS

            # # add the control to the interactive marker
            int_marker.controls.append(rotate_control)

            rotate_control = InteractiveMarkerControl()
            rotate_control.orientation.w = 1
            rotate_control.orientation.x = 0
            rotate_control.orientation.y = 0
            rotate_control.orientation.z = 1
            rotate_control.name = "move_y"
            rotate_control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS
            int_marker.controls.append(rotate_control)
            # add the interactive marker to our collection &
            # tell the server to call processFeedback() when feedback arrives for it
            self.server.insert(int_marker, self.processFeedback)

            self.coord_IMs[area_name][str(i)] = {"x": 0, "y": 0}

            # 'commit' changes and send to all clients
            self.server.applyChanges()

        return BuildingMapAreaResponse('OK')