diff --git a/consai_ros2/consai_visualizer/resource/visualizer.ui b/consai_ros2/consai_visualizer/resource/visualizer.ui index a02a3d780..3f50a49ef 100644 --- a/consai_ros2/consai_visualizer/resource/visualizer.ui +++ b/consai_ros2/consai_visualizer/resource/visualizer.ui @@ -39,7 +39,7 @@ - Connection + ping Qt::AlignCenter @@ -49,7 +49,7 @@ - Battery + 電圧 Qt::AlignCenter @@ -59,7 +59,7 @@ - Error + リターン Qt::AlignCenter @@ -95,24 +95,24 @@ - ConnectionStatus + - Qt::AlignCenter - + - TextLabel + - - - + + - TextLabel + - @@ -145,21 +145,21 @@ - ConnectionStatus + - - + - TextLabel + - - - + + - TextLabel + - @@ -183,7 +183,7 @@ - + @@ -192,21 +192,21 @@ - ConnectionStatus + - - + - TextLabel + - - - + + - TextLabel + - @@ -227,7 +227,7 @@ - + @@ -236,21 +236,21 @@ - ConnectionStatus + - - + - TextLabel + - - - + + - TextLabel + - @@ -280,21 +280,21 @@ - ConnectionStatus + - - + - TextLabel + - - - + + - TextLabel + - @@ -324,21 +324,21 @@ - ConnectionStatus + - - + - TextLabel + - - - + + - TextLabel + - @@ -368,21 +368,21 @@ - ConnectionStatus + - - + - TextLabel + - - - + + - TextLabel + - @@ -412,21 +412,21 @@ - ConnectionStatus + - - + - TextLabel + - - - + + - TextLabel + - @@ -456,21 +456,21 @@ - ConnectionStatus + - - + - TextLabel + - - - + + - TextLabel + - @@ -500,21 +500,21 @@ - ConnectionStatus + - - + - TextLabel + - - - + + - TextLabel + - @@ -544,21 +544,21 @@ - ConnectionStatus + - - + - TextLabel + - - - + + - TextLabel + - @@ -588,21 +588,21 @@ - ConnectionStatus + - - + - TextLabel + - - - + + - TextLabel + - diff --git a/consai_ros2/consai_visualizer/src/consai_visualizer/visualizer.py b/consai_ros2/consai_visualizer/src/consai_visualizer/visualizer.py index 844c47798..bab03681e 100644 --- a/consai_ros2/consai_visualizer/src/consai_visualizer/visualizer.py +++ b/consai_ros2/consai_visualizer/src/consai_visualizer/visualizer.py @@ -28,7 +28,7 @@ from crane_visualization_interfaces.msg import ObjectsArray from python_qt_binding import loadUi from python_qt_binding.QtCore import QPointF, Qt, QTimer -from python_qt_binding.QtWidgets import QTreeWidgetItem, QWidget +from python_qt_binding.QtWidgets import QTreeWidgetItem, QWidget, QFrame from qt_gui.plugin import Plugin import rclpy from robocup_ssl_msgs.msg import BallReplacement, Replacement, RobotReplacement @@ -125,7 +125,7 @@ def __init__(self, context): self._reset_timer.timeout.connect(self._update_robot_synthetics) self._reset_timer.start(1000) - self.latest_battery_voltage = [0] * 16 + self.latest_battery_voltage = [-1] * 16 # self._widget.pushButton.clicked.connect(self.publish) self._widget.session_injection_comboBox.addItem("simple_ai") @@ -179,6 +179,8 @@ def _session_injection(self): self._pub_session_injection.publish(msg) def _callback_feedback(self, msg): + self.latest_return_counter = [-1] * 16 + self.latest_battery_voltage = [-1] * 16 for feedback in msg.feedback: try: self.latest_battery_voltage[feedback.robot_id] = feedback.voltage[0] @@ -186,6 +188,10 @@ def _callback_feedback(self, msg): except AttributeError: # 初期化より先にコールバックが呼ばれてしまうことがあるため、エラーを回避する pass + try: + self.latest_return_counter[feedback.robot_id] = feedback.counter + except AttributeError: + pass # for synthetics def _callback_ping(self, msg): @@ -335,12 +341,19 @@ def _update_robot_synthetics(self): for i in range(16): # 電圧 try: - getattr(self._widget, f"robot{i}_voltage").setText( - "{:.2f}".format(self.latest_battery_voltage[i]) - ) + label = getattr(self._widget, f"robot{i}_voltage") + if self.latest_battery_voltage[i] == -1: + label.setText("-") + label.setLineWidth(0) + else: + label.setText("{:.2f}".format(self.latest_battery_voltage[i])) + label.setLineWidth(1) + label.setFrameStyle(QFrame.Box | QFrame.Plain) except AttributeError: try: - getattr(self._widget, f"robot{i}_voltage").setText(str(0.0)) + label = getattr(self._widget, f"robot{i}_voltage") + label.setText("-") + label.setLineWidth(0) except AttributeError: pass pass @@ -349,14 +362,34 @@ def _update_robot_synthetics(self): try: # 一旦全て"-"で埋める for i in range(12): - getattr(self._widget, f"robot{i}_connection_status").setText("-") + label = getattr(self._widget, f"robot{i}_connection_status") + label.setText("-") + label.setLineWidth(0) for ping_status in self.ping.ping: - getattr( + label = getattr( self._widget, f"robot{ping_status.robot_id}_connection_status" - ).setText("{:.1f}ms".format(ping_status.ping_ms)) + ) + label.setText("{:.1f}ms".format(ping_status.ping_ms)) + label.setLineWidth(1) + label.setFrameStyle(QFrame.Box | QFrame.Plain) except AttributeError: try: - getattr(self._widget, f"robot{i}_connection_status").setText("-") + label = getattr(self._widget, f"robot{i}_connection_status") + label.setText("-") + label.setLineWidth(0) except AttributeError: pass pass + + try: + for i in range(12): + label = getattr(self._widget, f"robot{i}_counter") + if self.latest_return_counter[i] == -1: + label.setText("-") + label.setLineWidth(0) + else: + label.setText(str(self.latest_return_counter[i])) + label.setLineWidth(1) + label.setFrameStyle(QFrame.Box | QFrame.Plain) + except AttributeError: + pass diff --git a/crane_msgs/msg/control/RobotCommand.msg b/crane_msgs/msg/control/RobotCommand.msg index 0e3fcdab7..bd1cef3fc 100755 --- a/crane_msgs/msg/control/RobotCommand.msg +++ b/crane_msgs/msg/control/RobotCommand.msg @@ -29,7 +29,7 @@ geometry_msgs/Pose2D current_pose bool enable_local_feedback float32 target_theta -float32 omega_limit 100.0 +float32 omega_limit 10.0 float32 latency_ms 0.0 diff --git a/crane_robot_receiver/src/robot_receiver_node.cpp b/crane_robot_receiver/src/robot_receiver_node.cpp index f97594fff..7dccdb70c 100644 --- a/crane_robot_receiver/src/robot_receiver_node.cpp +++ b/crane_robot_receiver/src/robot_receiver_node.cpp @@ -28,7 +28,7 @@ struct RobotInterfaceConfig auto makeConfig(uint8_t id) -> RobotInterfaceConfig { RobotInterfaceConfig config; - config.ip = "224.5.20.100"; + config.ip = std::format("224.5.20.{}", id + 100); config.port = 50100 + id; return config; } diff --git a/crane_sender/src/ibis_sender_node.cpp b/crane_sender/src/ibis_sender_node.cpp index 187406a98..f3a85d753 100644 --- a/crane_sender/src/ibis_sender_node.cpp +++ b/crane_sender/src/ibis_sender_node.cpp @@ -158,7 +158,7 @@ class IbisSenderNode : public SenderBase packet.stop_emergency = command.stop_flag; packet.acceleration_limit = command.local_planner_config.max_acceleration + 1.0; packet.linear_velocity_limit = command.local_planner_config.max_velocity; - packet.angular_velocity_limit = 10.; + packet.angular_velocity_limit = command.omega_limit; packet.prioritize_move = true; packet.prioritize_accurate_acceleration = true; diff --git a/crane_world_model_publisher/include/crane_world_model_publisher/world_model_publisher.hpp b/crane_world_model_publisher/include/crane_world_model_publisher/world_model_publisher.hpp index 83167a997..75242ef47 100644 --- a/crane_world_model_publisher/include/crane_world_model_publisher/world_model_publisher.hpp +++ b/crane_world_model_publisher/include/crane_world_model_publisher/world_model_publisher.hpp @@ -132,10 +132,14 @@ class WorldModelPublisherComponent : public rclcpp::Node double ball_placement_target_y; - bool ball_detected[20] = {}; + bool ball_sensor_detected[20] = {}; crane_msgs::msg::BallInfo ball_info; + std::deque ball_info_history; + + rclcpp::Time last_ball_detect_time; + std::vector robot_info[2]; std::unique_ptr geometry_receiver; diff --git a/crane_world_model_publisher/src/world_model_publisher.cpp b/crane_world_model_publisher/src/world_model_publisher.cpp index 324dadcbd..92061b146 100644 --- a/crane_world_model_publisher/src/world_model_publisher.cpp +++ b/crane_world_model_publisher/src/world_model_publisher.cpp @@ -68,7 +68,7 @@ WorldModelPublisherComponent::WorldModelPublisherComponent(const rclcpp::NodeOpt if (feedback->ball_sensor) { contact.last_contacted_time = now; } - ball_detected[robot.robot_id] = feedback->ball_sensor; + ball_sensor_detected[robot.robot_id] = feedback->ball_sensor; } } }); @@ -78,7 +78,7 @@ WorldModelPublisherComponent::WorldModelPublisherComponent(const rclcpp::NodeOpt if (our_color == Color::BLUE) { auto now = rclcpp::Clock().now(); for (auto status : msg->robots_status) { - ball_detected[status.robot_id] = status.infrared; + ball_sensor_detected[status.robot_id] = status.infrared; auto & contact = robot_info[static_cast(our_color)][status.robot_id].ball_contact; contact.current_time = now; @@ -95,7 +95,7 @@ WorldModelPublisherComponent::WorldModelPublisherComponent(const rclcpp::NodeOpt if (our_color == Color::YELLOW) { auto now = rclcpp::Clock().now(); for (auto status : msg->robots_status) { - ball_detected[status.robot_id] = status.infrared; + ball_sensor_detected[status.robot_id] = status.infrared; auto & contact = robot_info[static_cast(our_color)][status.robot_id].ball_contact; contact.current_time = now; @@ -205,6 +205,12 @@ void WorldModelPublisherComponent::on_udp_timer() if (packet.has_geometry()) { visionGeometryCallback(packet.geometry()); } + if (packet.has_detection()) { + int balls_size = packet.detection().balls().size(); + if (0 > balls_size) { + last_ball_detect_time = now(); + } + } } } } @@ -264,6 +270,24 @@ void WorldModelPublisherComponent::visionDetectionsCallback(const TrackedFrame & ball_info.disappeared = false; } else { ball_info.detected = false; + + // ball disappeared 判定 + int ball_info_history_size = ball_info_history.size(); + if (1 > ball_info_history_size) { + auto last_ball_info_history = ball_info_history[ball_info_history_size - 1]; + // double elapsed_time_since_last_detected = tracked_frame.timestamp() - last_ball_info_history.detection_time; + double elapsed_time_since_last_detected = (now() - last_ball_detect_time).seconds(); + + // 0.5secビジョンから見えていなければ見失った + if (0.5 < elapsed_time_since_last_detected) { + ball_info.disappeared = true; + } + } + } + + ball_info_history.emplace_back(ball_info); + if (ball_info_history.size() > 10) { + ball_info_history.pop_front(); } has_vision_updated = true; @@ -303,11 +327,12 @@ void WorldModelPublisherComponent::publishWorldModel() wm.is_yellow = (our_color == Color::YELLOW); wm.on_positive_half = on_positive_half; wm.is_emplace_positive_side = is_emplace_positive_side; - wm.ball_info = ball_info; wm.our_max_allowed_bots = our_max_allowed_bots; wm.their_max_allowed_bots = their_max_allowed_bots; updateBallContact(); + wm.ball_info = ball_info; + ball_history.push_back(Point(wm.ball_info.pose.x, wm.ball_info.pose.y)); if (ball_history.size() > history_size) { ball_history.pop_front(); @@ -455,12 +480,6 @@ void WorldModelPublisherComponent::publishWorldModel() void WorldModelPublisherComponent::updateBallContact() { auto now = rclcpp::Clock().now(); - static std::deque ball_info_history; - - ball_info_history.emplace_back(ball_info); - if (ball_info_history.size() > 10) { - ball_info_history.pop_front(); - } // bool pre_is_our_ball = std::exchange(is_our_ball, false); is_their_ball = false; @@ -524,12 +543,32 @@ void WorldModelPublisherComponent::updateBallContact() // ローカルセンサーの情報でボール情報を更新 for (std::size_t i = 0; i < robot_info[static_cast(our_color)].size(); i++) { - // ボールがロボットに近いときのみ接触とみなす(誤作動防止) double ball_distance = std::hypot( ball_info.pose.x - robot_info[static_cast(our_color)][i].pose.x, ball_info.pose.y - robot_info[static_cast(our_color)][i].pose.y); + // ビジョンがボールを見失っているときにボールセンサが反応している間は、接触しているものとみなす。 if ( - ball_detected[i] && not robot_info[static_cast(our_color)][i].disappeared && + ball_sensor_detected[i] && not robot_info[static_cast(our_color)][i].disappeared && + ball_info.disappeared) { + // ビジョンはボール見失っているけどロボットが保持しているので、ロボットの座標にボールがあることにする + + Point center_to_kicker = + getNormVec(robot_info[static_cast(our_color)][i].pose.theta) * 0.09; + ball_info.pose.x = + robot_info[static_cast(our_color)][i].pose.x + center_to_kicker.x(); + ball_info.pose.y = + robot_info[static_cast(our_color)][i].pose.y + center_to_kicker.y(); + + robot_info[static_cast(our_color)][i].ball_contact.is_vision_source = false; + robot_info[static_cast(our_color)][i].ball_contact.current_time = now; + robot_info[static_cast(our_color)][i].ball_contact.last_contacted_time = now; + if (not is_our_ball) { + std::cout << "敵ボール接触" << std::endl; + is_our_ball = true; + ball_event_detected = true; + } + } else if ( + ball_sensor_detected[i] && not robot_info[static_cast(our_color)][i].disappeared && ball_distance < 0.3) { robot_info[static_cast(our_color)][i].ball_contact.is_vision_source = false; robot_info[static_cast(our_color)][i].ball_contact.current_time = now;