experimental feature: ball prediction added
This commit is contained in:
parent
1183addab3
commit
500e7d5d64
|
|
@ -0,0 +1,23 @@
|
|||
<launch>
|
||||
<!-- ArUco Tag Detection Node -->
|
||||
<node name="camera_publisher" pkg="ball_tracking" type="camera_publisher.py" output="screen" />
|
||||
|
||||
<!-- ArUco Tag Detection Node -->
|
||||
<node name="aruco_area" pkg="ball_tracking" type="aruco_area.py" output="screen" />
|
||||
|
||||
<!-- Ball Tracking Node -->
|
||||
<node name="tracker_aruco" pkg="ball_tracking" type="tracker_aruco.py" output="screen" />
|
||||
|
||||
<!-- Ball Tracking Node -->
|
||||
<node name="tracker_aruco_idk" pkg="ball_tracking" type="tracker_aruco_idk.py" output="screen" />
|
||||
|
||||
<!-- Ball Tracking Node -->
|
||||
<node name="paddle_action" pkg="ball_tracking" type="paddle_action.py" output="screen" />
|
||||
|
||||
<!-- Ball Tracking Node -->
|
||||
<node name="ball_prediction" pkg="ball_tracking" type="ball_prediction.py" output="screen" />
|
||||
|
||||
<!-- Ball Tracking Node -->
|
||||
<node name="prediction_monitor" pkg="ball_tracking" type="prediction_monitor.py" output="screen" />
|
||||
</launch>
|
||||
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import rospy
|
||||
from geometry_msgs.msg import Point
|
||||
from std_msgs.msg import Header
|
||||
import numpy as np
|
||||
|
||||
class BallMovementPredictor:
|
||||
def __init__(self):
|
||||
rospy.init_node('ball_movement_predictor', anonymous=True)
|
||||
|
||||
self.ball_positions = []
|
||||
self.forecast_length = 5 # Predict the ball's position 5 steps into the future
|
||||
|
||||
# Subscriber to the ball's current position
|
||||
self.ball_sub = rospy.Subscriber('/ball_coordinates', Point, self.ball_callback)
|
||||
|
||||
# Publisher for the ball's forecasted future position
|
||||
self.forecast_pub = rospy.Publisher('/ball_forecast', Point, queue_size=10)
|
||||
|
||||
def ball_callback(self, msg):
|
||||
# Update the list of recent ball positions
|
||||
self.ball_positions.append((msg.x, msg.y))
|
||||
|
||||
# Keep only the last N positions for prediction
|
||||
if len(self.ball_positions) > 5:
|
||||
self.ball_positions.pop(0)
|
||||
|
||||
# Predict the ball's future position and publish it
|
||||
forecasted_position = self.predict_future_position()
|
||||
if forecasted_position is not None:
|
||||
forecast_msg = Point(x=forecasted_position[0], y=forecasted_position[1], z=0)
|
||||
self.forecast_pub.publish(forecast_msg)
|
||||
|
||||
def predict_future_position(self):
|
||||
if len(self.ball_positions) < 2:
|
||||
return None # Not enough data to predict
|
||||
|
||||
# Simple linear prediction based on the last two positions
|
||||
x_positions, y_positions = zip(*self.ball_positions)
|
||||
x_velocity = x_positions[-1] - x_positions[-2]
|
||||
y_velocity = y_positions[-1] - y_positions[-2]
|
||||
|
||||
forecasted_x = x_positions[-1] + x_velocity * self.forecast_length
|
||||
forecasted_y = y_positions[-1] + y_velocity * self.forecast_length
|
||||
|
||||
return (forecasted_x, forecasted_y)
|
||||
|
||||
def run(self):
|
||||
rospy.spin()
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
predictor = BallMovementPredictor()
|
||||
predictor.run()
|
||||
except rospy.ROSInterruptException:
|
||||
pass
|
||||
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import rospy
|
||||
import cv2
|
||||
from cv_bridge import CvBridge
|
||||
from sensor_msgs.msg import Image
|
||||
from geometry_msgs.msg import Point
|
||||
|
||||
class BallPredictionVisualizer:
|
||||
def __init__(self):
|
||||
rospy.init_node('ball_prediction_visualizer', anonymous=True)
|
||||
|
||||
self.bridge = CvBridge()
|
||||
self.forecasted_position_aruco = None
|
||||
self.aruco_origin = None
|
||||
|
||||
self.image_sub = rospy.Subscriber('/camera_image', Image, self.image_callback)
|
||||
self.forecast_sub = rospy.Subscriber('/ball_forecast', Point, self.forecast_callback)
|
||||
self.origin_sub = rospy.Subscriber('/aruco_origin', Point, self.origin_callback)
|
||||
|
||||
def forecast_callback(self, msg):
|
||||
self.forecasted_position_aruco = (int(msg.x), int(msg.y))
|
||||
|
||||
def origin_callback(self, msg):
|
||||
self.aruco_origin = (int(msg.x), int(msg.y))
|
||||
|
||||
def image_callback(self, msg):
|
||||
cv_image = self.bridge.imgmsg_to_cv2(msg, "bgr8")
|
||||
|
||||
if self.aruco_origin:
|
||||
# Draw the ArUco origin for verification
|
||||
cv2.circle(cv_image, self.aruco_origin, 10, (0, 255, 0), -1) # Green dot for the origin
|
||||
|
||||
if self.forecasted_position_aruco and self.aruco_origin:
|
||||
# Adjust for the origin and possibly invert the y-axis
|
||||
adjusted_position = (
|
||||
self.forecasted_position_aruco[0] + self.aruco_origin[0],
|
||||
self.forecasted_position_aruco[1] + self.aruco_origin[1]
|
||||
)
|
||||
cv2.circle(cv_image, adjusted_position, 10, (0, 0, 255), -1) # Red dot for the predicted position
|
||||
|
||||
cv2.imshow("Ball Prediction", cv_image)
|
||||
cv2.waitKey(1)
|
||||
|
||||
def run(self):
|
||||
rospy.spin()
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
visualizer = BallPredictionVisualizer()
|
||||
visualizer.run()
|
||||
except rospy.ROSInterruptException:
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
Loading…
Reference in New Issue