Example #1
0
	def ros_to_can(self, data_array: List[int], values: Argumentable):
		"""
			Apply current parameter into data array from given values
		"""

		if not values.has(self.name):
			raise MissingParameterException(self.name)

		value = values.get(self.name, int)

		if value < 0 or value > 255 ** self.size:
			rospy.logerr("unable to encode {} value {}".format(self.name, value))
			return

		if self.size == 1:
			data_array[self.byte_start] = value
		elif self.size == 2:
			data_array[self.byte_start] = value >> 8
			data_array[self.byte_start + 1] = value & 0x00FF
		else:
			raise Exception("size not handled yet, go back to coding")
class Action:
	action_id = 0

	def __init__(self):
		# Object id
		self.action_id = Action.action_id
		Action.action_id += 1

		self.name: str = ""
		self.native = False
		self.points = 0

		self.arguments: Argumentable = []
		self.requirements: List[ObjectRequirement] = []
		self.parent: Union['ActionGroup', None] = None
	
		self.__action_point: Union[ActionPoint, None] = None
		self.__action_point_origin: Union[ActionPoint, None] = None

		self.__state = ActionStatus.IDLE

	def set_side(self, side: int):
		# Set side as argument
		self.arguments.set("_side", side)

	def __before_children__(self, context):
		# Get parent arguments
		if context.parent is not None:
			self.arguments.extend(context.parent.arguments)

	def __parsed__(self, context):
		self.arguments = Argumentable().from_list(self.arguments)

		# Apply context to values
		self.points = self.__contextualized_value(str(self.points), int)

		for key in self.arguments.keys():
			self.arguments.set(key, self.__contextualized_value(self.arguments.get(key)))
		
	def __contextualized_value(self, value: str, cast: Type = str):
		# TODO check
		if len(value) > 0 and value[0] == "@":
			if self.arguments.has(value[1:]):
				return cast(self.arguments.get(value[1:]))
			else:
				return cast()
		else:
			return cast(value) if len(value) > 0 else cast()

	@property
	def state(self) -> int:
		return self.__state

	@state.setter
	def state(self, state: int):
		self.__state = state

		# If not resuming, we propagate to parent
		if state != ActionStatus.IDLE and self.parent != None:
			self.parent.state = state


	def total_points(self):
		return self.points

	
	def action_point(self, origin: Pose2D) -> ActionPoint:
		'''
			Compute the initial and final point of the action.
			Calls associated performer service to let it compute the point based on args 
		'''

		# Check if previously saved for this origin
		if self.__action_point == None or self.__action_point_origin != origin:
			point_service = rospy.ServiceProxy(
				get_action_point_service(self.name),
				ComputeActionPoint
			)
			
			# Wait 2s max for service
			point_service.wait_for_service(2)

			try:
				self.__action_point = point_service(origin, self.arguments.to_list()).action_point
				self.__action_point_origin = origin
			except rospy.ServiceException:
				rospy.logerr("unable to process action point for {}".format(self.name))

		return self.__action_point

	def travel_distance(self, origin: Pose2D) -> float:
		'''Compute the estimated distance to travel before the robot reach the end of the action'''
		point = self.action_point(origin)

		# Return euclidian distance
		return math.sqrt(
			pow(point.start.x - origin.x, 2) +
			pow(point.start.y - origin.y, 2)
		) + math.sqrt(
			pow(point.start.x - point.end.x, 2) +
			pow(point.start.y - point.end.y, 2)
		)


	def priority(self, origin: Pose2D) -> float:
		points = self.total_points()
		distance = self.travel_distance(origin)

		if distance == 0: # handle divide by 0
			return math.inf
		else:
			return points * points / distance
			
	def get_optimal(self, robot_pos: Pose2D) -> ActionChoice:
		"""
			Returns the optimal choice of native action from this action
		"""

		# In a simple action, only two cases : action unavailable or not
		if self.state != ActionStatus.IDLE:
			return ActionChoice(None, -1)
		else:
			return ActionChoice(self, self.priority(robot_pos))

	def color(self, text):
		if self.state == ActionStatus.PAUSED:
			# Yellow
			return '\033[33m' + text + '\033[0m'
		elif self.state == ActionStatus.DONE:
			# Green
			return '\033[32m' + text + '\033[0m'
		elif self.state == ActionStatus.IDLE:
			# Grey
			return '\033[90m' + text + '\033[0m'
		else:
			# Red
			return '\033[31m' + text + '\033[0m'

	def __str__(self):
		return "{} points={} {{{}}}".format(
			self.color("[{}@{}]".format(self.name, self.action_id)), self.total_points(), self.arguments.__str__()
#			self.color("[{}@{}]".format(self.name, self.action_id)), self.total_points(), ""
		)