From bb7b1f5ca638406b32f609a54e7994c657454f70 Mon Sep 17 00:00:00 2001 From: marinaog <116306804+marinaog@users.noreply.github.com> Date: Wed, 23 Apr 2025 16:09:15 +0200 Subject: [PATCH 01/46] Added ball communication (global and local coordinates still need to be fixed) --- crates/bifrost/src/serialization/codec.rs | 38 ++++++++ crates/bifrost/src/serialization/nalgebra.rs | 33 ++++++- yggdrasil/src/behavior/roles/striker.rs | 7 +- yggdrasil/src/communication/team.rs | 2 + .../vision/ball_detection/communication.rs | 87 +++++++++++++++++++ yggdrasil/src/vision/ball_detection/mod.rs | 5 ++ 6 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 yggdrasil/src/vision/ball_detection/communication.rs diff --git a/crates/bifrost/src/serialization/codec.rs b/crates/bifrost/src/serialization/codec.rs index 6c29df7c7..efda7ea21 100644 --- a/crates/bifrost/src/serialization/codec.rs +++ b/crates/bifrost/src/serialization/codec.rs @@ -404,6 +404,44 @@ where } } +impl Encode for Option +where + T: Encode, +{ + fn encode(&self, mut write: impl Write) -> Result<()> { + match self { + Some(inner) => { + write.write_u8(1)?; + inner.encode(write) + }, + None => Ok(write.write_u8(0)?), + } + } + + fn encode_len(&self) -> usize { + match self { + Some(inner) => inner.encode_len() + 1, + None => 1, + } + } +} + +impl Decode for Option +where + T: Decode +{ + fn decode(mut read: impl Read) -> Result + where + Self: Sized, + { + match read.read_u8()? { + 0 => Ok(None), + 1 => Ok(Some(T::decode(read)?)), + n => Err(Error::InvalidVariantDiscriminant(n as usize, "Option")), + } + } +} + impl Encode for Vec where T: Encode, diff --git a/crates/bifrost/src/serialization/nalgebra.rs b/crates/bifrost/src/serialization/nalgebra.rs index d49cf3ec4..d785004bd 100644 --- a/crates/bifrost/src/serialization/nalgebra.rs +++ b/crates/bifrost/src/serialization/nalgebra.rs @@ -2,7 +2,8 @@ use std::io::{Read, Write}; -use nalgebra::{Dim, Matrix, Scalar, Storage, StorageMut}; +use nalgebra::{Dim, Matrix, Scalar, Storage, StorageMut, + allocator::Allocator, base::default_allocator::DefaultAllocator, DinName, OPoint}; use super::{Decode, Encode}; @@ -56,6 +57,36 @@ where } } +impl Encode for OPoint +where + T: Scalar + Encode, + D: DimName, + DefaultAllocator: Allocator, +{ + fn encode(&self, mut write: impl Write) -> Result<()> { + self.coords.encode(&mut write) + } + + fn encode_len(&self) -> usize { + self.coords.encode_len() + } +} + +impl Decode for OPoint +where + T: Scalar + Decode, + D: DimName, + DefaultAllocator: Allocator, + >::Buffer: Default, +{ + fn decode(mut read: impl Read) -> Result + where + Self: Sized, + { + Ok(Matrix::into(Matrix::decode(&mut read)?)) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/yggdrasil/src/behavior/roles/striker.rs b/yggdrasil/src/behavior/roles/striker.rs index 1a20f6336..7c5ea28f8 100644 --- a/yggdrasil/src/behavior/roles/striker.rs +++ b/yggdrasil/src/behavior/roles/striker.rs @@ -11,7 +11,7 @@ use crate::{ localization::RobotPose, motion::walking_engine::step::Step, nao::{NaoManager, Priority}, - vision::ball_detection::ball_tracker::BallTracker, + vision::ball_detection::TeamBallPosition, }; const WALK_WITH_BALL_ANGLE: f32 = 0.3; @@ -38,10 +38,11 @@ pub fn striker_role( mut commands: Commands, pose: Res, layout_config: Res, - ball_tracker: Res, + team_ball_position: Res, mut nao_manager: ResMut, + mut state: ResMut, ) { - let Some(relative_ball) = ball_tracker.stationary_ball() else { + let Some(relative_ball) = team_ball_position.0 else { commands.set_behavior(RlStrikerSearchBehavior); return; }; diff --git a/yggdrasil/src/communication/team.rs b/yggdrasil/src/communication/team.rs index a08b7ec7f..a866d03c3 100644 --- a/yggdrasil/src/communication/team.rs +++ b/yggdrasil/src/communication/team.rs @@ -4,6 +4,7 @@ use std::time::Duration; use bevy::prelude::{App, *}; use miette::IntoDiagnostic; +use nalgebra as na; use crate::core::config::showtime::ShowtimeConfig; use crate::prelude::*; @@ -188,6 +189,7 @@ pub enum TeamMessage { Ping, Pong, DetectedWhistle, + DetectedBall(Option>), RecognizedRefereePose(RefereePose), } diff --git a/yggdrasil/src/vision/ball_detection/communication.rs b/yggdrasil/src/vision/ball_detection/communication.rs new file mode 100644 index 000000000..3365997fc --- /dev/null +++ b/yggdrasil/src/vision/ball_detection/communication.rs @@ -0,0 +1,87 @@ +use bevy::prelude::*; +use nalgebra::{self as na, Point2}; + +use crate::communication::{TeamCommunication, TeamMessage}; + +// Import camera proposals +use super::{ball_tracker::BallTracker, Hypothesis}; + +// Constant for the minimum acceptable change +const MIN_CHANGE: f32 = 0.1; + +pub struct CommunicatedBallsPlugin; + +impl Plugin for CommunicatedBallsPlugin { + fn build(&self, app: &mut App) { + app.init_resource::() + .init_resource::() + .add_systems(Update, communicate_balls_system); + } +} + +#[derive(Resource, Default, Debug)] +pub struct TeamBallPosition(pub Option>); + +#[derive(Resource, Debug, Default)] +pub struct CommunicatedBalls { + /// For keeping track what position we've sent out. + sent: Option>, +} + +impl CommunicatedBalls { + /// Check it the position has changed enough from last frame. + fn change_enough(&mut self, ball: &Option>) -> bool { + match (ball, &self.sent) { + (None, None) => false, + (None, Some(_)) => true, + (Some(_), None) => true, + (Some(old), Some(new)) => na::distance(old, new) > MIN_CHANGE, + } + } + + /// Send your ball position (even if it's None) as a message. + fn send_message(&mut self, ball_position: Option>, tc: &mut TeamCommunication) { + tc.outbound_mut() + .update_or_push(TeamMessage::DetectedBall(ball_position)) + .expect("Unable to encode detected ball"); + self.sent = ball_position; + } + + /// Receive messages. + // 2.A.a. If no other robot are detecting a ball, we return the same None we had + // 2.A.b. If there are other robots detecting a ball, we take one from theirs as our own. + fn receive_messages(comms: &mut TeamCommunication) -> Option> { + let mut received_ball = None; + + while let Some((_, _, ball)) = comms.inbound_mut().take_map(|_, _, what| match what { + TeamMessage::DetectedBall(ball) => Some(*ball), + _ => None, + }) { + received_ball = received_ball.or(ball); + } + + received_ball + } +} + +fn communicate_balls_system( + mut communicated_balls: ResMut, + mut tc: ResMut, + ball_tracker: Res, + mut team_ball_position: ResMut, +) { + let optional_ball_position = if let Hypothesis::Stationary(_) = ball_tracker.cutoff() { + Some(ball_tracker.state().0) + } else { + None + }; + + // 1. Check if it has changed enough and if so, we send a message. + // let optional_ball_position = ball_position.map(|ball_position| ball_position.0); + if communicated_balls.change_enough(&optional_ball_position) { + communicated_balls.send_message(optional_ball_position, &mut tc) + } + + team_ball_position.0 = + optional_ball_position.or_else(|| CommunicatedBalls::receive_messages(&mut tc)); +} \ No newline at end of file diff --git a/yggdrasil/src/vision/ball_detection/mod.rs b/yggdrasil/src/vision/ball_detection/mod.rs index c038731f8..ef389338a 100644 --- a/yggdrasil/src/vision/ball_detection/mod.rs +++ b/yggdrasil/src/vision/ball_detection/mod.rs @@ -2,6 +2,7 @@ pub mod ball_tracker; pub mod classifier; +mod communication; pub mod proposal; use std::{sync::Arc, time::Duration}; @@ -9,6 +10,8 @@ use std::{sync::Arc, time::Duration}; pub use ball_tracker::BallHypothesis; use ball_tracker::BallTracker; use bevy::prelude::*; +use communication::CommunicatedBallsPlugin; +pub use communication::TeamBallPosition; use heimdall::{Bottom, CameraLocation, Top}; use nidhogg::types::{FillExt, LeftEye, color}; use proposal::BallProposalConfigs; @@ -31,6 +34,7 @@ pub struct BallDetectionPlugin; impl Plugin for BallDetectionPlugin { fn build(&self, app: &mut App) { + app.add_plugins(CommunicatedBallsPlugin); app.init_config::(); app.add_plugins(( proposal::BallProposalPlugin::::default(), @@ -144,6 +148,7 @@ fn log_3d_balls( if let BallHypothesis::Stationary(max_variance) = state { let pos = robot_pose.robot_to_world(&ball_tracker.state()); + if last_logged.is_none_or(|last_logged_cycle| last_ball_tracker_update > last_logged_cycle) { *last_logged = Some(last_ball_tracker_update); From 06d696c3412f127d23c8d04ef2790333451f2122 Mon Sep 17 00:00:00 2001 From: marinaog <116306804+marinaog@users.noreply.github.com> Date: Wed, 23 Apr 2025 16:50:30 +0200 Subject: [PATCH 02/46] Transformation local<->global coordinates added --- .../src/vision/ball_detection/communication.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/yggdrasil/src/vision/ball_detection/communication.rs b/yggdrasil/src/vision/ball_detection/communication.rs index 3365997fc..8a05aca73 100644 --- a/yggdrasil/src/vision/ball_detection/communication.rs +++ b/yggdrasil/src/vision/ball_detection/communication.rs @@ -50,7 +50,7 @@ impl CommunicatedBalls { /// Receive messages. // 2.A.a. If no other robot are detecting a ball, we return the same None we had // 2.A.b. If there are other robots detecting a ball, we take one from theirs as our own. - fn receive_messages(comms: &mut TeamCommunication) -> Option> { + fn receive_messages(comms: &mut TeamCommunication, pose: &RobotPose) -> Option> { let mut received_ball = None; while let Some((_, _, ball)) = comms.inbound_mut().take_map(|_, _, what| match what { @@ -59,8 +59,8 @@ impl CommunicatedBalls { }) { received_ball = received_ball.or(ball); } - - received_ball + // If we received a ball, transform it from world coordinates to robot coordinates + received_ball.map(|ball| pose.world_to_robot(&ball)) } } @@ -68,7 +68,8 @@ fn communicate_balls_system( mut communicated_balls: ResMut, mut tc: ResMut, ball_tracker: Res, - mut team_ball_position: ResMut, + mut team_ball_position: ResMut, + pose: Res, ) { let optional_ball_position = if let Hypothesis::Stationary(_) = ball_tracker.cutoff() { Some(ball_tracker.state().0) @@ -79,9 +80,14 @@ fn communicate_balls_system( // 1. Check if it has changed enough and if so, we send a message. // let optional_ball_position = ball_position.map(|ball_position| ball_position.0); if communicated_balls.change_enough(&optional_ball_position) { - communicated_balls.send_message(optional_ball_position, &mut tc) + if let Some(local_ball_pos) = optional_ball_position { + let transformed_position = optional_ball_position.map(|pos| pose.robot_to_world(&pos)); + communicated_balls.send_message(transformed_position, &mut tc) + } else { + communicated_balls.send_message(None, &mut tc); // optional_ball_position = None in this case + } } team_ball_position.0 = - optional_ball_position.or_else(|| CommunicatedBalls::receive_messages(&mut tc)); + optional_ball_position.or_else(|| CommunicatedBalls::receive_messages(&mut tc, &pose)); } \ No newline at end of file From 577b56c04c9292e7e0256455dc68d3ecfbfd03b3 Mon Sep 17 00:00:00 2001 From: marinaog <116306804+marinaog@users.noreply.github.com> Date: Wed, 23 Apr 2025 17:17:08 +0200 Subject: [PATCH 03/46] Typo fixed --- crates/bifrost/src/serialization/nalgebra.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bifrost/src/serialization/nalgebra.rs b/crates/bifrost/src/serialization/nalgebra.rs index d785004bd..2bc565cb6 100644 --- a/crates/bifrost/src/serialization/nalgebra.rs +++ b/crates/bifrost/src/serialization/nalgebra.rs @@ -3,7 +3,7 @@ use std::io::{Read, Write}; use nalgebra::{Dim, Matrix, Scalar, Storage, StorageMut, - allocator::Allocator, base::default_allocator::DefaultAllocator, DinName, OPoint}; + allocator::Allocator, base::default_allocator::DefaultAllocator, DimName, OPoint}; use super::{Decode, Encode}; From 89037d85cbad241eafdf00b192b816324e931b34 Mon Sep 17 00:00:00 2001 From: Julia Blaauboer Date: Wed, 23 Apr 2025 17:20:25 +0200 Subject: [PATCH 04/46] fromat --- crates/bifrost/src/serialization/codec.rs | 4 ++-- crates/bifrost/src/serialization/nalgebra.rs | 6 ++++-- .../src/vision/ball_detection/communication.rs | 15 +++++++++------ yggdrasil/src/vision/ball_detection/mod.rs | 2 +- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/crates/bifrost/src/serialization/codec.rs b/crates/bifrost/src/serialization/codec.rs index efda7ea21..0692b2c5e 100644 --- a/crates/bifrost/src/serialization/codec.rs +++ b/crates/bifrost/src/serialization/codec.rs @@ -413,7 +413,7 @@ where Some(inner) => { write.write_u8(1)?; inner.encode(write) - }, + } None => Ok(write.write_u8(0)?), } } @@ -428,7 +428,7 @@ where impl Decode for Option where - T: Decode + T: Decode, { fn decode(mut read: impl Read) -> Result where diff --git a/crates/bifrost/src/serialization/nalgebra.rs b/crates/bifrost/src/serialization/nalgebra.rs index 2bc565cb6..497d1f156 100644 --- a/crates/bifrost/src/serialization/nalgebra.rs +++ b/crates/bifrost/src/serialization/nalgebra.rs @@ -2,8 +2,10 @@ use std::io::{Read, Write}; -use nalgebra::{Dim, Matrix, Scalar, Storage, StorageMut, - allocator::Allocator, base::default_allocator::DefaultAllocator, DimName, OPoint}; +use nalgebra::{ + Dim, DimName, Matrix, OPoint, Scalar, Storage, StorageMut, allocator::Allocator, + base::default_allocator::DefaultAllocator, +}; use super::{Decode, Encode}; diff --git a/yggdrasil/src/vision/ball_detection/communication.rs b/yggdrasil/src/vision/ball_detection/communication.rs index 8a05aca73..2d35dc66d 100644 --- a/yggdrasil/src/vision/ball_detection/communication.rs +++ b/yggdrasil/src/vision/ball_detection/communication.rs @@ -4,7 +4,7 @@ use nalgebra::{self as na, Point2}; use crate::communication::{TeamCommunication, TeamMessage}; // Import camera proposals -use super::{ball_tracker::BallTracker, Hypothesis}; +use super::{Hypothesis, ball_tracker::BallTracker}; // Constant for the minimum acceptable change const MIN_CHANGE: f32 = 0.1; @@ -50,7 +50,10 @@ impl CommunicatedBalls { /// Receive messages. // 2.A.a. If no other robot are detecting a ball, we return the same None we had // 2.A.b. If there are other robots detecting a ball, we take one from theirs as our own. - fn receive_messages(comms: &mut TeamCommunication, pose: &RobotPose) -> Option> { + fn receive_messages( + comms: &mut TeamCommunication, + pose: &RobotPose, + ) -> Option> { let mut received_ball = None; while let Some((_, _, ball)) = comms.inbound_mut().take_map(|_, _, what| match what { @@ -59,8 +62,8 @@ impl CommunicatedBalls { }) { received_ball = received_ball.or(ball); } - // If we received a ball, transform it from world coordinates to robot coordinates - received_ball.map(|ball| pose.world_to_robot(&ball)) + // If we received a ball, transform it from world coordinates to robot coordinates + received_ball.map(|ball| pose.world_to_robot(&ball)) } } @@ -68,7 +71,7 @@ fn communicate_balls_system( mut communicated_balls: ResMut, mut tc: ResMut, ball_tracker: Res, - mut team_ball_position: ResMut, + mut team_ball_position: ResMut, pose: Res, ) { let optional_ball_position = if let Hypothesis::Stationary(_) = ball_tracker.cutoff() { @@ -90,4 +93,4 @@ fn communicate_balls_system( team_ball_position.0 = optional_ball_position.or_else(|| CommunicatedBalls::receive_messages(&mut tc, &pose)); -} \ No newline at end of file +} diff --git a/yggdrasil/src/vision/ball_detection/mod.rs b/yggdrasil/src/vision/ball_detection/mod.rs index ef389338a..a68568dd2 100644 --- a/yggdrasil/src/vision/ball_detection/mod.rs +++ b/yggdrasil/src/vision/ball_detection/mod.rs @@ -148,7 +148,7 @@ fn log_3d_balls( if let BallHypothesis::Stationary(max_variance) = state { let pos = robot_pose.robot_to_world(&ball_tracker.state()); - + if last_logged.is_none_or(|last_logged_cycle| last_ball_tracker_update > last_logged_cycle) { *last_logged = Some(last_ball_tracker_update); From 9bc628aae10b508b703fe7d7874da846cbe3325f Mon Sep 17 00:00:00 2001 From: Julia Blaauboer Date: Wed, 23 Apr 2025 17:33:05 +0200 Subject: [PATCH 05/46] should be fine eh --- yggdrasil/src/behavior/roles/striker.rs | 1 - yggdrasil/src/vision/ball_detection/communication.rs | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/yggdrasil/src/behavior/roles/striker.rs b/yggdrasil/src/behavior/roles/striker.rs index 7c5ea28f8..2cf770bfd 100644 --- a/yggdrasil/src/behavior/roles/striker.rs +++ b/yggdrasil/src/behavior/roles/striker.rs @@ -40,7 +40,6 @@ pub fn striker_role( layout_config: Res, team_ball_position: Res, mut nao_manager: ResMut, - mut state: ResMut, ) { let Some(relative_ball) = team_ball_position.0 else { commands.set_behavior(RlStrikerSearchBehavior); diff --git a/yggdrasil/src/vision/ball_detection/communication.rs b/yggdrasil/src/vision/ball_detection/communication.rs index 2d35dc66d..98d290d51 100644 --- a/yggdrasil/src/vision/ball_detection/communication.rs +++ b/yggdrasil/src/vision/ball_detection/communication.rs @@ -1,10 +1,13 @@ use bevy::prelude::*; use nalgebra::{self as na, Point2}; -use crate::communication::{TeamCommunication, TeamMessage}; +use crate::{ + communication::{TeamCommunication, TeamMessage}, + localization::RobotPose, +}; // Import camera proposals -use super::{Hypothesis, ball_tracker::BallTracker}; +use super::ball_tracker::{BallHypothesis, BallTracker}; // Constant for the minimum acceptable change const MIN_CHANGE: f32 = 0.1; @@ -74,7 +77,7 @@ fn communicate_balls_system( mut team_ball_position: ResMut, pose: Res, ) { - let optional_ball_position = if let Hypothesis::Stationary(_) = ball_tracker.cutoff() { + let optional_ball_position = if let BallHypothesis::Stationary(_) = ball_tracker.cutoff() { Some(ball_tracker.state().0) } else { None From b32b8d4a40995bba53ea38161d500e097dd94afa Mon Sep 17 00:00:00 2001 From: Julia Blaauboer Date: Wed, 23 Apr 2025 17:38:40 +0200 Subject: [PATCH 06/46] shut up clippy --- yggdrasil/src/vision/ball_detection/communication.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/yggdrasil/src/vision/ball_detection/communication.rs b/yggdrasil/src/vision/ball_detection/communication.rs index 98d290d51..174ad1aba 100644 --- a/yggdrasil/src/vision/ball_detection/communication.rs +++ b/yggdrasil/src/vision/ball_detection/communication.rs @@ -86,12 +86,8 @@ fn communicate_balls_system( // 1. Check if it has changed enough and if so, we send a message. // let optional_ball_position = ball_position.map(|ball_position| ball_position.0); if communicated_balls.change_enough(&optional_ball_position) { - if let Some(local_ball_pos) = optional_ball_position { - let transformed_position = optional_ball_position.map(|pos| pose.robot_to_world(&pos)); - communicated_balls.send_message(transformed_position, &mut tc) - } else { - communicated_balls.send_message(None, &mut tc); // optional_ball_position = None in this case - } + let transformed_position = optional_ball_position.map(|pos| pose.robot_to_world(&pos)); + communicated_balls.send_message(transformed_position, &mut tc); } team_ball_position.0 = From 4720f6b01b26de90112feda37262e3a8e3ee732b Mon Sep 17 00:00:00 2001 From: Julia Blaauboer Date: Wed, 23 Apr 2025 17:44:12 +0200 Subject: [PATCH 07/46] weeeee --- yggdrasil/src/vision/ball_detection/communication.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yggdrasil/src/vision/ball_detection/communication.rs b/yggdrasil/src/vision/ball_detection/communication.rs index 174ad1aba..ec0d65795 100644 --- a/yggdrasil/src/vision/ball_detection/communication.rs +++ b/yggdrasil/src/vision/ball_detection/communication.rs @@ -33,7 +33,7 @@ pub struct CommunicatedBalls { impl CommunicatedBalls { /// Check it the position has changed enough from last frame. - fn change_enough(&mut self, ball: &Option>) -> bool { + fn change_enough(&mut self, ball: Option<&na::Point2>) -> bool { match (ball, &self.sent) { (None, None) => false, (None, Some(_)) => true, @@ -85,7 +85,7 @@ fn communicate_balls_system( // 1. Check if it has changed enough and if so, we send a message. // let optional_ball_position = ball_position.map(|ball_position| ball_position.0); - if communicated_balls.change_enough(&optional_ball_position) { + if communicated_balls.change_enough(optional_ball_position.as_ref()) { let transformed_position = optional_ball_position.map(|pos| pose.robot_to_world(&pos)); communicated_balls.send_message(transformed_position, &mut tc); } From 0ae3e2a2c1b2ba0c05cc5677ad7b1dd8184d5f7b Mon Sep 17 00:00:00 2001 From: Gijs de Jong Date: Wed, 23 Apr 2025 18:32:20 +0200 Subject: [PATCH 08/46] save ball position --- yggdrasil/src/behavior/roles/striker.rs | 2 ++ .../src/vision/ball_detection/communication.rs | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/yggdrasil/src/behavior/roles/striker.rs b/yggdrasil/src/behavior/roles/striker.rs index 2cf770bfd..b0fea3849 100644 --- a/yggdrasil/src/behavior/roles/striker.rs +++ b/yggdrasil/src/behavior/roles/striker.rs @@ -46,6 +46,8 @@ pub fn striker_role( return; }; + println!("we have a ball"); + let absolute_ball = pose.robot_to_world(&relative_ball); let ball_angle = pose.angle_to(&absolute_ball); let ball_distance = relative_ball.coords.norm(); diff --git a/yggdrasil/src/vision/ball_detection/communication.rs b/yggdrasil/src/vision/ball_detection/communication.rs index ec0d65795..76811878e 100644 --- a/yggdrasil/src/vision/ball_detection/communication.rs +++ b/yggdrasil/src/vision/ball_detection/communication.rs @@ -76,12 +76,9 @@ fn communicate_balls_system( ball_tracker: Res, mut team_ball_position: ResMut, pose: Res, + mut last_received: Local>>, ) { - let optional_ball_position = if let BallHypothesis::Stationary(_) = ball_tracker.cutoff() { - Some(ball_tracker.state().0) - } else { - None - }; + let optional_ball_position = ball_tracker.stationary_ball(); // 1. Check if it has changed enough and if so, we send a message. // let optional_ball_position = ball_position.map(|ball_position| ball_position.0); @@ -90,6 +87,9 @@ fn communicate_balls_system( communicated_balls.send_message(transformed_position, &mut tc); } - team_ball_position.0 = - optional_ball_position.or_else(|| CommunicatedBalls::receive_messages(&mut tc, &pose)); + if let Some(new_pos) = CommunicatedBalls::receive_messages(&mut tc, &pose) { + *last_received = Some(new_pos); + } + + team_ball_position.0 = optional_ball_position.or_else(|| *last_received); } From e8a337fabfdb48629e63aa70a8a3ca951574428f Mon Sep 17 00:00:00 2001 From: Gijs de Jong Date: Wed, 23 Apr 2025 18:44:31 +0200 Subject: [PATCH 09/46] stuff --- .../src/vision/ball_detection/communication.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/yggdrasil/src/vision/ball_detection/communication.rs b/yggdrasil/src/vision/ball_detection/communication.rs index 76811878e..ad84a5ce1 100644 --- a/yggdrasil/src/vision/ball_detection/communication.rs +++ b/yggdrasil/src/vision/ball_detection/communication.rs @@ -3,7 +3,9 @@ use nalgebra::{self as na, Point2}; use crate::{ communication::{TeamCommunication, TeamMessage}, + core::debug::DebugContext, localization::RobotPose, + nao::Cycle, }; // Import camera proposals @@ -77,6 +79,8 @@ fn communicate_balls_system( mut team_ball_position: ResMut, pose: Res, mut last_received: Local>>, + ctx: DebugContext, + cycle: Res, ) { let optional_ball_position = ball_tracker.stationary_ball(); @@ -92,4 +96,15 @@ fn communicate_balls_system( } team_ball_position.0 = optional_ball_position.or_else(|| *last_received); + + if let Some(pos) = team_ball_position.0 { + let global = pose.robot_to_world(&pos); + ctx.log_with_cycle( + "/team_ball", + *cycle, + &rerun::Points3D::new([(global.x, global.y, 0.01)]) + .with_radii([0.1]) + .with_labels(["team_ball"]), + ); + } } From 3bff0f8dc146c82bf63d4a1144d8adee3369e79a Mon Sep 17 00:00:00 2001 From: marinaog <116306804+marinaog@users.noreply.github.com> Date: Mon, 19 May 2025 22:57:03 +0200 Subject: [PATCH 10/46] fixing clippy --- yggdrasil/src/vision/ball_detection/communication.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yggdrasil/src/vision/ball_detection/communication.rs b/yggdrasil/src/vision/ball_detection/communication.rs index ad84a5ce1..f93cb0d23 100644 --- a/yggdrasil/src/vision/ball_detection/communication.rs +++ b/yggdrasil/src/vision/ball_detection/communication.rs @@ -9,7 +9,7 @@ use crate::{ }; // Import camera proposals -use super::ball_tracker::{BallHypothesis, BallTracker}; +use super::ball_tracker::{BallTracker}; // Constant for the minimum acceptable change const MIN_CHANGE: f32 = 0.1; From 612106b82136eeaaad8acf140be25a0c2e7ff704 Mon Sep 17 00:00:00 2001 From: marinaog <116306804+marinaog@users.noreply.github.com> Date: Mon, 19 May 2025 23:08:00 +0200 Subject: [PATCH 11/46] merging conflict --- yggdrasil/src/communication/team.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/yggdrasil/src/communication/team.rs b/yggdrasil/src/communication/team.rs index a866d03c3..0b2c977fb 100644 --- a/yggdrasil/src/communication/team.rs +++ b/yggdrasil/src/communication/team.rs @@ -5,6 +5,7 @@ use std::time::Duration; use bevy::prelude::{App, *}; use miette::IntoDiagnostic; use nalgebra as na; +use tracing::{debug, warn}; use crate::core::config::showtime::ShowtimeConfig; use crate::prelude::*; From 460e64e5170d12346150651f9a3ba6b30ea284c2 Mon Sep 17 00:00:00 2001 From: marinaog <116306804+marinaog@users.noreply.github.com> Date: Mon, 19 May 2025 23:17:23 +0200 Subject: [PATCH 12/46] clippy me this one --- yggdrasil/src/vision/ball_detection/communication.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yggdrasil/src/vision/ball_detection/communication.rs b/yggdrasil/src/vision/ball_detection/communication.rs index f93cb0d23..cd3b75482 100644 --- a/yggdrasil/src/vision/ball_detection/communication.rs +++ b/yggdrasil/src/vision/ball_detection/communication.rs @@ -9,7 +9,7 @@ use crate::{ }; // Import camera proposals -use super::ball_tracker::{BallTracker}; +use super::ball_tracker::BallTracker; // Constant for the minimum acceptable change const MIN_CHANGE: f32 = 0.1; @@ -72,6 +72,7 @@ impl CommunicatedBalls { } } +#[allow(clippy::too_many_arguments)] fn communicate_balls_system( mut communicated_balls: ResMut, mut tc: ResMut, From 089fcd6c498f0ca540c081061eb773db259eed2a Mon Sep 17 00:00:00 2001 From: marinaog <116306804+marinaog@users.noreply.github.com> Date: Wed, 21 May 2025 12:32:27 +0200 Subject: [PATCH 13/46] Removed print check --- yggdrasil/src/behavior/roles/striker.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/yggdrasil/src/behavior/roles/striker.rs b/yggdrasil/src/behavior/roles/striker.rs index b0fea3849..a9de758f2 100644 --- a/yggdrasil/src/behavior/roles/striker.rs +++ b/yggdrasil/src/behavior/roles/striker.rs @@ -46,7 +46,6 @@ pub fn striker_role( return; }; - println!("we have a ball"); let absolute_ball = pose.robot_to_world(&relative_ball); let ball_angle = pose.angle_to(&absolute_ball); From 327454c1c9cb218138e91f9eb743d81e82838b4e Mon Sep 17 00:00:00 2001 From: marinaog <116306804+marinaog@users.noreply.github.com> Date: Wed, 21 May 2025 13:36:01 +0200 Subject: [PATCH 14/46] cargo fmt doesnt forgive --- yggdrasil/src/behavior/roles/striker.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/yggdrasil/src/behavior/roles/striker.rs b/yggdrasil/src/behavior/roles/striker.rs index a9de758f2..2cf770bfd 100644 --- a/yggdrasil/src/behavior/roles/striker.rs +++ b/yggdrasil/src/behavior/roles/striker.rs @@ -46,7 +46,6 @@ pub fn striker_role( return; }; - let absolute_ball = pose.robot_to_world(&relative_ball); let ball_angle = pose.angle_to(&absolute_ball); let ball_distance = relative_ball.coords.norm(); From 41e33b62c2cc38a525cadacf5e7b6c6d3d40fe67 Mon Sep 17 00:00:00 2001 From: Juell Sprott Date: Thu, 17 Jul 2025 20:50:44 +0200 Subject: [PATCH 15/46] timeout team ball after constant amount of cycles without communicated ball --- .../vision/ball_detection/communication.rs | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/yggdrasil/src/vision/ball_detection/communication.rs b/yggdrasil/src/vision/ball_detection/communication.rs index cd3b75482..4f868a4b5 100644 --- a/yggdrasil/src/vision/ball_detection/communication.rs +++ b/yggdrasil/src/vision/ball_detection/communication.rs @@ -14,12 +14,22 @@ use super::ball_tracker::BallTracker; // Constant for the minimum acceptable change const MIN_CHANGE: f32 = 0.1; +// constant for last received team ball position +const LAST_RECEIVED: usize = 500; + pub struct CommunicatedBallsPlugin; +#[derive(Resource, Default, Debug)] +pub struct LastReceivedBall{ + pub position: Option>, + pub cycles_since_last_received: usize, +} + impl Plugin for CommunicatedBallsPlugin { fn build(&self, app: &mut App) { app.init_resource::() .init_resource::() + .init_resource::() .add_systems(Update, communicate_balls_system); } } @@ -79,7 +89,7 @@ fn communicate_balls_system( ball_tracker: Res, mut team_ball_position: ResMut, pose: Res, - mut last_received: Local>>, + mut last_received: ResMut, ctx: DebugContext, cycle: Res, ) { @@ -93,10 +103,23 @@ fn communicate_balls_system( } if let Some(new_pos) = CommunicatedBalls::receive_messages(&mut tc, &pose) { - *last_received = Some(new_pos); + println!("Received new ball position: {:?}", new_pos); + last_received.position = Some(new_pos); + } else { + last_received.cycles_since_last_received += 1; + println!( + "No team ball position received for {} cycles", + last_received.cycles_since_last_received + ); + if last_received.cycles_since_last_received > LAST_RECEIVED { + last_received.position = None; + last_received.cycles_since_last_received = 0; + } } - team_ball_position.0 = optional_ball_position.or_else(|| *last_received); + team_ball_position.0 = optional_ball_position.or_else(|| last_received.position); + println!("last received position: {:?}", last_received.position); + println!("team ball position: {:?}", team_ball_position.0); if let Some(pos) = team_ball_position.0 { let global = pose.robot_to_world(&pos); @@ -107,5 +130,11 @@ fn communicate_balls_system( .with_radii([0.1]) .with_labels(["team_ball"]), ); + } else { + ctx.log_with_cycle( + "/team_ball", + *cycle, + &rerun::Clear::recursive(), + ); } } From b529862b2a2faf313f2637338142dbb03e62e59c Mon Sep 17 00:00:00 2001 From: Juell Sprott Date: Fri, 18 Jul 2025 01:23:45 +0200 Subject: [PATCH 16/46] formatting --- yggdrasil/src/vision/ball_detection/communication.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/yggdrasil/src/vision/ball_detection/communication.rs b/yggdrasil/src/vision/ball_detection/communication.rs index 4f868a4b5..8fa5e7015 100644 --- a/yggdrasil/src/vision/ball_detection/communication.rs +++ b/yggdrasil/src/vision/ball_detection/communication.rs @@ -20,7 +20,7 @@ const LAST_RECEIVED: usize = 500; pub struct CommunicatedBallsPlugin; #[derive(Resource, Default, Debug)] -pub struct LastReceivedBall{ +pub struct LastReceivedBall { pub position: Option>, pub cycles_since_last_received: usize, } @@ -131,10 +131,6 @@ fn communicate_balls_system( .with_labels(["team_ball"]), ); } else { - ctx.log_with_cycle( - "/team_ball", - *cycle, - &rerun::Clear::recursive(), - ); + ctx.log_with_cycle("/team_ball", *cycle, &rerun::Clear::recursive()); } } From 44a12b6a730775be72b53e1c846c22def153878f Mon Sep 17 00:00:00 2001 From: Juell Sprott Date: Fri, 18 Jul 2025 01:46:08 +0200 Subject: [PATCH 17/46] remove print statements --- yggdrasil/src/vision/ball_detection/communication.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/yggdrasil/src/vision/ball_detection/communication.rs b/yggdrasil/src/vision/ball_detection/communication.rs index 8fa5e7015..cec9c476a 100644 --- a/yggdrasil/src/vision/ball_detection/communication.rs +++ b/yggdrasil/src/vision/ball_detection/communication.rs @@ -103,7 +103,6 @@ fn communicate_balls_system( } if let Some(new_pos) = CommunicatedBalls::receive_messages(&mut tc, &pose) { - println!("Received new ball position: {:?}", new_pos); last_received.position = Some(new_pos); } else { last_received.cycles_since_last_received += 1; @@ -118,8 +117,6 @@ fn communicate_balls_system( } team_ball_position.0 = optional_ball_position.or_else(|| last_received.position); - println!("last received position: {:?}", last_received.position); - println!("team ball position: {:?}", team_ball_position.0); if let Some(pos) = team_ball_position.0 { let global = pose.robot_to_world(&pos); From 9531ff971fee22bc5ca1b8d86bea447c6bb6a855 Mon Sep 17 00:00:00 2001 From: Juell Sprott Date: Fri, 18 Jul 2025 01:47:37 +0200 Subject: [PATCH 18/46] test balltracker crate addition --- yggdrasil/src/behavior/roles/striker.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yggdrasil/src/behavior/roles/striker.rs b/yggdrasil/src/behavior/roles/striker.rs index 9e980e53a..cff3ed44a 100644 --- a/yggdrasil/src/behavior/roles/striker.rs +++ b/yggdrasil/src/behavior/roles/striker.rs @@ -14,6 +14,8 @@ use crate::{ vision::ball_detection::TeamBallPosition, }; +use crate::vision::ball_detection::ball_tracker::BallTracker; + const WALK_WITH_BALL_ANGLE: f32 = 0.3; const ALIGN_WITH_BALL_DISTANCE: f32 = 0.3; From 4e40ac81e589c98bc461e9d2815416cd24a7b4bd Mon Sep 17 00:00:00 2001 From: Juell Sprott Date: Fri, 18 Jul 2025 01:53:06 +0200 Subject: [PATCH 19/46] remove balltracker import --- yggdrasil/src/behavior/roles/striker.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/yggdrasil/src/behavior/roles/striker.rs b/yggdrasil/src/behavior/roles/striker.rs index cff3ed44a..9e980e53a 100644 --- a/yggdrasil/src/behavior/roles/striker.rs +++ b/yggdrasil/src/behavior/roles/striker.rs @@ -14,8 +14,6 @@ use crate::{ vision::ball_detection::TeamBallPosition, }; -use crate::vision::ball_detection::ball_tracker::BallTracker; - const WALK_WITH_BALL_ANGLE: f32 = 0.3; const ALIGN_WITH_BALL_DISTANCE: f32 = 0.3; From 0a2e8adbbd5af289e172cb3f6c47f12e4c6c5904 Mon Sep 17 00:00:00 2001 From: Juell Sprott Date: Fri, 18 Jul 2025 01:57:57 +0200 Subject: [PATCH 20/46] change team ball to detected ball in striker.rs --- yggdrasil/src/behavior/roles/striker.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yggdrasil/src/behavior/roles/striker.rs b/yggdrasil/src/behavior/roles/striker.rs index 9e980e53a..3cdc9aea5 100644 --- a/yggdrasil/src/behavior/roles/striker.rs +++ b/yggdrasil/src/behavior/roles/striker.rs @@ -51,10 +51,10 @@ pub fn striker_role( mut commands: Commands, pose: Res, layout_config: Res, - team_ball_position: Res, + detected_ball_position: Res, mut nao_manager: ResMut, ) { - let Some(relative_ball) = team_ball_position.0 else { + let Some(relative_ball) = detected_ball_position.0 else { nao_manager.set_right_eye_led(RightEye::fill(color::f32::GREEN), Priority::default()); commands.set_behavior(RlStrikerSearchBehavior); return; From 0ca9331bc6f1e7edaf71936825f41df4b5623ad5 Mon Sep 17 00:00:00 2001 From: Juell Sprott Date: Fri, 18 Jul 2025 13:23:33 +0200 Subject: [PATCH 21/46] fix striker.rs not being merged with main --- yggdrasil/src/behavior/roles/striker.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yggdrasil/src/behavior/roles/striker.rs b/yggdrasil/src/behavior/roles/striker.rs index 9f485748d..8fc3c5210 100644 --- a/yggdrasil/src/behavior/roles/striker.rs +++ b/yggdrasil/src/behavior/roles/striker.rs @@ -157,12 +157,12 @@ pub fn striker_role( //TODO: Make this a separate stand-alone behavior fn set_play( mut commands: Commands, - ball_tracker: Res, + detected_ball_position: Res, pose: Res, behavior_state: Res>, walk: Option>, ) { - let Some(relative_ball) = ball_tracker.stationary_ball() else { + let Some(relative_ball) = detected_ball_position.0 else { return; }; let absolute_ball = pose.robot_to_world(&relative_ball); From 51712e67ece880d7fd9705bd24594800c9608d53 Mon Sep 17 00:00:00 2001 From: Juell Sprott Date: Fri, 18 Jul 2025 18:11:38 +0200 Subject: [PATCH 22/46] remove cycle time thresholding on communicated ball message age --- .../src/vision/ball_detection/communication.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/yggdrasil/src/vision/ball_detection/communication.rs b/yggdrasil/src/vision/ball_detection/communication.rs index cec9c476a..1ea8f3155 100644 --- a/yggdrasil/src/vision/ball_detection/communication.rs +++ b/yggdrasil/src/vision/ball_detection/communication.rs @@ -14,15 +14,11 @@ use super::ball_tracker::BallTracker; // Constant for the minimum acceptable change const MIN_CHANGE: f32 = 0.1; -// constant for last received team ball position -const LAST_RECEIVED: usize = 500; - pub struct CommunicatedBallsPlugin; #[derive(Resource, Default, Debug)] pub struct LastReceivedBall { pub position: Option>, - pub cycles_since_last_received: usize, } impl Plugin for CommunicatedBallsPlugin { @@ -105,15 +101,7 @@ fn communicate_balls_system( if let Some(new_pos) = CommunicatedBalls::receive_messages(&mut tc, &pose) { last_received.position = Some(new_pos); } else { - last_received.cycles_since_last_received += 1; - println!( - "No team ball position received for {} cycles", - last_received.cycles_since_last_received - ); - if last_received.cycles_since_last_received > LAST_RECEIVED { - last_received.position = None; - last_received.cycles_since_last_received = 0; - } + last_received.position = None; } team_ball_position.0 = optional_ball_position.or_else(|| last_received.position); From 0cf29bc0dcd93a490eb90eb15248bf7f3824cfc4 Mon Sep 17 00:00:00 2001 From: Juell Sprott Date: Sat, 19 Jul 2025 01:57:04 +0200 Subject: [PATCH 23/46] fix imports --- yggdrasil/src/behavior/roles/striker.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yggdrasil/src/behavior/roles/striker.rs b/yggdrasil/src/behavior/roles/striker.rs index 1d6da65f7..dc67504ad 100644 --- a/yggdrasil/src/behavior/roles/striker.rs +++ b/yggdrasil/src/behavior/roles/striker.rs @@ -9,7 +9,7 @@ use crate::{ LookMode, LostBallSearch, RlStrikerSearchBehavior, StandLookAt, Walk, WalkTo, WalkToBall, }, - engine::{in_role, BehaviorState, CommandsBehaviorExt, RoleState, Roles}, + engine::{BehaviorState, CommandsBehaviorExt, RoleState, Roles, in_role}, primary_state::PrimaryState, }, core::config::{ @@ -19,7 +19,7 @@ use crate::{ localization::RobotPose, motion::{step_planner::Target, walking_engine::step::Step}, nao::{NaoManager, Priority}, - vision::ball_detection::{ball_tracker::BallTracker, TeamBallPosition}, + vision::ball_detection::{TeamBallPosition, ball_tracker::BallTracker}, }; use std::time::Duration; @@ -98,6 +98,7 @@ fn reset_striker_role(mut nao_manager: ResMut) { nao_manager.set_right_eye_led(RightEye::fill(color::f32::EMPTY), Priority::default()); } +#[allow(clippy::too_many_arguments)] pub fn striker_role( mut commands: Commands, pose: Res, @@ -108,7 +109,6 @@ pub fn striker_role( lost_ball_timer: Option>, time: Res