Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
2e390f5
Put uROS agent back in hardware launches
osu-uwrt-bot2 Sep 28, 2025
15984d3
Better FFC cal
osu-uwrt-bot2 Oct 25, 2025
07cb544
Post-Sean tunes
osu-uwrt-bot2 Oct 31, 2025
2c3ceb6
Better tuning, zed picture taker enabled
osu-uwrt-bot2 Nov 2, 2025
8e76197
Updated picture taker to handle param changes
osu-uwrt-bot2 Nov 3, 2025
b709a6f
ZED X mini for ffc
osu-uwrt-bot2 Nov 6, 2025
7945712
ZEDXm FFC
osu-uwrt-bot2 Nov 11, 2025
1e55bff
Disable DFC for now
osu-uwrt-bot2 Nov 11, 2025
4920a2f
Slightly better tunes
osu-uwrt-bot2 Nov 21, 2025
d3cd486
ZEDXm cal
osu-uwrt-bot2 Nov 21, 2025
3141c9d
Stable tunes with good convergence + good FF
osu-uwrt-bot2 Nov 22, 2025
105d057
Updated COM
Effo12345 Dec 6, 2025
03f2fa8
Cursed awful ff tune + controller tuning
Effo12345 Dec 6, 2025
39279c5
Really good RPAC tunes with fixed angular accumulators
Effo12345 Jan 13, 2026
026b8b0
Tune w/ acoustics, 5/6 torps rpac
zehdari Jan 20, 2026
b8b7694
Fix logging level
osu-uwrt-bot2 Feb 9, 2026
e120cbc
FFC depth limit
osu-uwrt-bot2 Feb 23, 2026
3bebfd4
Claw COM and frame
osu-uwrt-bot2 Mar 2, 2026
b905e3e
Updated zed launches
osu-uwrt-bot2 Mar 2, 2026
7b61ef8
Revert to pre-claw COM
osu-uwrt-bot2 Mar 29, 2026
37eb900
Charuco board cal
osu-uwrt-bot2 Apr 13, 2026
1af94cb
SetString service
Effo12345 Apr 13, 2026
931bc74
add StartBinaryClassifier srv
zehdari Jun 7, 2026
aa39af2
Fix classifier param names
Effo12345 Jun 12, 2026
589f9a1
Tirpak 1 claw frame
osu-uwrt-bot2 Jun 15, 2026
36695d3
Tirpak 1 DFC cal
osu-uwrt-bot2 Jun 15, 2026
a289d04
Fix feedforward
Effo12345 Jun 15, 2026
a989ec6
Take z from the IMU
Effo12345 Jun 15, 2026
67bd5e4
Merge branch 'BinaryClassifier' of github.com:osu-uwrt/riptide_core i…
Effo12345 Jun 15, 2026
175595f
Need IMU in the Z since depth is too slow
osu-uwrt-bot2 Jun 28, 2026
32e237f
Claw ff and ungaslight the torps
osu-uwrt-bot2 Jun 28, 2026
722a8b5
Reduce orin load
osu-uwrt-bot2 Jun 28, 2026
bb6822a
Actually use firmware stamp
osu-uwrt-bot2 Jun 28, 2026
9a249b2
Working pose and resolution
osu-uwrt-bot2 Jun 29, 2026
520a445
Merge pull request #63 from osu-uwrt/BinaryClassifier
osu-uwrt-bot2 Jul 3, 2026
b24fd9e
Good night tune
osu-uwrt-bot2 Jul 10, 2026
e1094b2
Better pitch damping
osu-uwrt-bot2 Jul 10, 2026
dc4b1ec
Acoustic sampling interface
zehdari Jul 10, 2026
6e9f44d
new topic
zehdari Jul 10, 2026
d9cea86
Added acoustics to hw launches
zehdari Jul 10, 2026
1a89fcf
Slight tuning, camera and torpedo pose
osu-uwrt-bot2 Jul 11, 2026
09d5c55
Different cal and depth mode
osu-uwrt-bot2 Jul 11, 2026
6be014e
Merge branch 'dev' into AmplitudeAcoustics
osu-uwrt-bot2 Jul 11, 2026
7c1d357
Don't pub result on multiple samples
Effo12345 Jul 11, 2026
ba8b292
More aggressive z and pitch
osu-uwrt-bot2 Jul 13, 2026
8a5993b
Pinger broker for persistent frequency
osu-uwrt-bot2 Jul 13, 2026
14dd805
Magnet link
osu-uwrt-bot2 Jul 15, 2026
f1498c1
Magnet link and semis 1 tunes
osu-uwrt-bot2 Jul 15, 2026
d32ee3d
Semis1 tunes
osu-uwrt-bot2 Jul 15, 2026
80cd5e1
remove percentile parameter in favor of mode parameter than can chang…
blakesmittty Jul 15, 2026
6f2c67b
make response messages more clear
blakesmittty Jul 15, 2026
eb57238
Slightly better tunes
osu-uwrt-bot2 Jul 15, 2026
a4f254b
Merge remote-tracking branch 'origin/pinger_sampling' into dev
osu-uwrt-bot2 Jul 15, 2026
ad2e881
Talos namespace
osu-uwrt-bot2 Jul 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions riptide_acoustics/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,27 @@ endif()
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(std_msgs REQUIRED)
find_package(std_srvs REQUIRED)
find_package(rclcpp REQUIRED)
find_package(tf2 REQUIRED)
find_package(tf2_ros REQUIRED)
find_package(geometry_msgs REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)

add_executable(run_acoustics src/Acoustics.cpp)

ament_target_dependencies(run_acoustics
std_msgs
geometry_msgs
rclcpp
tf2
tf2_ros)
std_msgs
std_srvs
rclcpp)

install(TARGETS run_acoustics
DESTINATION lib/${PROJECT_NAME}
)

install(DIRECTORY launch
DESTINATION share/${PROJECT_NAME}
)

#yoink files
file(GLOB src_py_files RELATIVE ${PROJECT_SOURCE_DIR} src/*.py)
install(PROGRAMS ${src_py_files}
Expand Down
23 changes: 23 additions & 0 deletions riptide_acoustics/launch/acoustics.launch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node

def generate_launch_description():
return LaunchDescription([
DeclareLaunchArgument(name="mode", default_value="max",
description="Mode of comparing buffer 0 and buffer 1 to find nearest pinger"),

Node(
package='riptide_acoustics',
executable='run_acoustics',
name='riptide_acoustics',
output='screen',
parameters=[
{
"mode": LaunchConfiguration("mode")
}
],
respawn=True
)
])
6 changes: 3 additions & 3 deletions riptide_acoustics/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>

<depend>riptide_msgs2</depend>
<depend>rclpy</depend>
<depend>tf2</depend>
<depend>rclcpp</depend>
<depend>std_msgs</depend>
<depend>std_srvs</depend>

<export>
<build_type>ament_cmake</build_type>
Expand Down
234 changes: 180 additions & 54 deletions riptide_acoustics/src/Acoustics.cpp
Original file line number Diff line number Diff line change
@@ -1,98 +1,224 @@
#include <memory>
#include <chrono>
#include <functional>


#include <vector>
#include <algorithm>
#include <numeric>
#include <string>

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/float32.hpp"
#include "geometry_msgs/msg/transform_stamped.hpp"
#include "geometry_msgs/msg/transform.hpp"

#include "tf2_ros/transform_listener.h"
#include "tf2_ros/buffer.h"
#include "tf2/exceptions.h"
#include "std_msgs/msg/bool.hpp"
#include "std_srvs/srv/trigger.hpp"

#define MODE_MAX_FALLBACK_DIFF 1000.0f
#define P_VALUE 95.0f

using namespace std::chrono_literals;
using std::placeholders::_1;
using namespace std::placeholders;

// 1) start_sample -> collect amplitudes for buffer 0
// 2) stop_sample -> close buffer 0
// 3) start_sample -> collect ampltudes for buffer 1
// 4) stop_sample -> close buffer 1, then compare and publish once to buffer_0_closer

class MinimalSubscriber : public rclcpp::Node
class Acoustics : public rclcpp::Node
{
public:
MinimalSubscriber()
Acoustics()
: Node("riptide_acoustics")
{
subscription_ = this->create_subscription<std_msgs::msg::Float32>(
"acoustics/delta_t", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
this->declare_parameter("mode", "avg");

ampSubscription = this->create_subscription<std_msgs::msg::Float32>(
"/talos/ivc/pinger/selected_freq_amp_stream", 10, std::bind(&Acoustics::ampCallback, this, _1));

resultPublisher = this->create_publisher<std_msgs::msg::Bool>(
"/talos/acoustics/buffer_0_closer", 10);

//initialize tf buffer and tf listener
tf_buffer_ = std::make_unique<tf2_ros::Buffer>(this->get_clock());
tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
resultTimer = this->create_wall_timer(
std::chrono::seconds(1), std::bind(&Acoustics::publishResult, this));

portToStarboardTransformTimer = this->create_wall_timer(1s, std::bind(&MinimalSubscriber::getPortToStarboardTransform, this));
startSampleService = this->create_service<std_srvs::srv::Trigger>(
"/talos/acoustics/start_sample", std::bind(&Acoustics::startSample, this, _1, _2));

stopSampleService = this->create_service<std_srvs::srv::Trigger>(
"/talos/acoustics/stop_sample", std::bind(&Acoustics::stopSample, this, _1, _2));
}

private:
void topic_callback(const std_msgs::msg::Float32::SharedPtr msg) const
void ampCallback(const std_msgs::msg::Float32::SharedPtr msg)
{
if (sampling) {
buffers[activeBuffer].push_back(msg->data);
}
}

void startSample(const std_srvs::srv::Trigger::Request::SharedPtr,
std_srvs::srv::Trigger::Response::SharedPtr response)
{
geometry_msgs::msg::TransformStamped t;

try {
t = tf_buffer_->lookupTransform(
"world", "talos/base_link",
tf2::TimePointZero);
} catch (const tf2::TransformException & ex) {
RCLCPP_INFO(
this->get_logger(), "Could not transform!");
if (sampling) {
response->success = false;
response->message = "Already sampling";
return;
}

buffers[activeBuffer].clear();
sampling = true;
haveResult = false;

response->success = true;
response->message = "Sampling into buffer " + std::to_string(activeBuffer);
RCLCPP_INFO(this->get_logger(), "Started sampling into buffer %d", activeBuffer);
}

void stopSample(const std_srvs::srv::Trigger::Request::SharedPtr,
std_srvs::srv::Trigger::Response::SharedPtr response)
{
if (!sampling) {
response->success = false;
response->message = "Not sampling";
return;
}

sampling = false;

RCLCPP_INFO(this->get_logger(), "Stopped sampling buffer %d with %zu samples",
activeBuffer, buffers[activeBuffer].size());

if (activeBuffer == 0) {
activeBuffer = 1;
response->success = true;
response->message = "With mode [" + this->get_parameter("mode").as_string() + "] Buffer 0 closed with " + std::to_string(buffers[0].size()) + " samples";
return;
}

RCLCPP_INFO(this->get_logger(), "X: %f", t.transform.translation.x);
// buffer 1 just closed, compare and reset
compareBuffers(response);
activeBuffer = 0;
}

std::string make_comparison_response(const std::string &mode) {
auto summary = [&](const std::string &mode_label) {
return "mode => [" + mode_label + "], result => buffer "
+ std::to_string(buffer0Closer ? 0 : 1)
+ " closer [buffer 0: " + std::to_string(result_0)
+ " buffer 1: " + std::to_string(result_1) + "]";
};

std::string resp = "";
if (mode == "avg") {
resp = summary("avg");
} else if (mode == "max") {
if (did_fallback_on_max) {
resp += "INFO: [FELLBACK TO AVG ON MAX MODE] ";
}
resp += summary("max");
} else if (mode == "p95") {
resp = summary("p95");
resp = "UNRECOGNIZED MODE, CHECK LAUNCH FILE OR SOMETHING ";
}
Comment on lines +114 to +117

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Fix unrecognized mode string overwrite for p95.

The p95 branch unconditionally overwrites the valid response summary with the "unrecognized mode" error string. Introduce an else block to properly route truly unrecognized modes.

🐛 Proposed fix
       } else if (mode == "p95") {
         resp = summary("p95");
-        resp = "UNRECOGNIZED MODE, CHECK LAUNCH FILE OR SOMETHING ";
+      } else {
+        resp = "UNRECOGNIZED MODE, CHECK LAUNCH FILE OR SOMETHING ";
       }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} else if (mode == "p95") {
resp = summary("p95");
resp = "UNRECOGNIZED MODE, CHECK LAUNCH FILE OR SOMETHING ";
}
} else if (mode == "p95") {
resp = summary("p95");
} else {
resp = "UNRECOGNIZED MODE, CHECK LAUNCH FILE OR SOMETHING ";
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@riptide_acoustics/src/Acoustics.cpp` around lines 114 - 117, Update the
mode-selection logic in Acoustics.cpp so the p95 branch retains the response
returned by summary("p95"). Move the "UNRECOGNIZED MODE" assignment into an else
branch associated with the recognized-mode checks, ensuring it runs only for
unsupported modes.

return resp;
}

void getPortToStarboardTransform()
void compareBuffers(std_srvs::srv::Trigger::Response::SharedPtr response)
{
//stamped msg
geometry_msgs::msg::TransformStamped stamped;
if (buffers[0].empty() || buffers[1].empty()) {
response->success = false;
response->message = "Cannot compare, buffer 0 has " + std::to_string(buffers[0].size()) +
" samples and buffer 1 has " + std::to_string(buffers[1].size());
RCLCPP_WARN(this->get_logger(), "%s", response->message.c_str());
return;
}

//get transform from tf buffer
try {
reduceBuffers(buffers[0], buffers[1], this->get_parameter("mode").as_string());
haveResult = true;
publishResult();

//TODO: change to port and starboard pod frames
stamped = tf_buffer_->lookupTransform("talos/pose_sensor_link", "talos/base_link", tf2::TimePointZero);

portToStarboardTransform = stamped.transform;
response->success = true;
response->message = make_comparison_response(this->get_parameter("mode").as_string());
// response->message = "mode[" + this->get_parameter("mode").as_string() + "]buffer " + std::to_string(buffer0Closer ? 0 : 1) +
// " closer (buffer 0: " + std::to_string(result_0) +
// ", buffer 1: " + std::to_string(result_1) + ")";
RCLCPP_INFO(this->get_logger(), "%s", response->message.c_str());
}

RCLCPP_INFO(this->get_logger(), "Successfuly collected port to starboard transform!");
} catch (const tf2::TransformException & ex) {
RCLCPP_INFO(
this->get_logger(), "Could collect port to starboard transform, retrying!");
void publishResult()
{
if (!haveResult) {
return;
}

portToStarboardTransformTimer->cancel();
std_msgs::msg::Bool msg;
msg.data = buffer0Closer;
resultPublisher->publish(msg);
}

void compare_avg_buffers(const std::vector<float> &buffer0, const std::vector<float> &buffer1) {
result_0 = std::accumulate(buffer0.begin(), buffer0.end(), 0.0) / buffer0.size();
result_1 = std::accumulate(buffer1.begin(), buffer1.end(), 0.0) / buffer1.size();
buffer0Closer = result_0 >= result_1;
}

rclcpp::Subscription<std_msgs::msg::Float32>::SharedPtr subscription_;
void compare_p95_buffers(const std::vector<float> &buffer0, const std::vector<float> &buffer1) {
// it's c++ so sorting is O(n) right? (fire bar - balke)
std::vector<float> sorted0 = buffer0;
std::vector<float> sorted1 = buffer1;
size_t idx_0 = static_cast<size_t>(std::clamp((double)P_VALUE, 0.0, 100.0) / 100.0 * (sorted0.size() - 1));
size_t idx_1 = static_cast<size_t>(std::clamp((double)P_VALUE, 0.0, 100.0) / 100.0 * (sorted1.size() - 1));
std::nth_element(sorted0.begin(), sorted0.begin() + idx_0, sorted0.end());
std::nth_element(sorted1.begin(), sorted1.begin() + idx_1, sorted1.end());
result_0 = sorted0[idx_0];
result_1 = sorted1[idx_1];
buffer0Closer = result_0 >= result_1;
}

void compare_max_buffers(const std::vector<float> &buffer0, const std::vector<float> &buffer1) {
result_0 = *std::max_element(buffer0.begin(), buffer0.end());
result_1 = *std::max_element(buffer1.begin(), buffer1.end());
if (std::abs(result_0 - result_1) < MODE_MAX_FALLBACK_DIFF) {
did_fallback_on_max = true;
compare_avg_buffers(buffer0, buffer1);
}
}
Comment on lines +176 to +180

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Set buffer0Closer and reset fallback flag when not falling back.

If the difference between the maximum values is greater than or equal to MODE_MAX_FALLBACK_DIFF, the function exits without calculating buffer0Closer. This leaves the comparison result unchanged from the previous run.

Additionally, did_fallback_on_max is never reset to false, causing subsequent successful max comparisons to falsely log that they fell back to the average mode.

🐛 Proposed fix to add the missing branch
       if (std::abs(result_0 - result_1) < MODE_MAX_FALLBACK_DIFF) {
         did_fallback_on_max = true;
         compare_avg_buffers(buffer0, buffer1);
+      } else {
+        did_fallback_on_max = false;
+        buffer0Closer = result_0 >= result_1;
       }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (std::abs(result_0 - result_1) < MODE_MAX_FALLBACK_DIFF) {
did_fallback_on_max = true;
compare_avg_buffers(buffer0, buffer1);
}
}
if (std::abs(result_0 - result_1) < MODE_MAX_FALLBACK_DIFF) {
did_fallback_on_max = true;
compare_avg_buffers(buffer0, buffer1);
} else {
did_fallback_on_max = false;
buffer0Closer = result_0 >= result_1;
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@riptide_acoustics/src/Acoustics.cpp` around lines 176 - 180, Update the
maximum-value comparison logic in the relevant acoustics function so the
non-fallback branch, where the difference is greater than or equal to
MODE_MAX_FALLBACK_DIFF, calculates and assigns buffer0Closer directly from the
maximum values and resets did_fallback_on_max to false. Preserve the existing
compare_avg_buffers behavior and true flag assignment for the fallback branch.


void reduceBuffers(const std::vector<float> &buffer0, const std::vector<float> &buffer1, std::string mode) {
if (mode == "avg") {
compare_avg_buffers(buffer0, buffer1);
}

if (mode == "max") {
compare_max_buffers(buffer0, buffer1);
}

//tf
std::shared_ptr<tf2_ros::TransformListener> tf_listener_{nullptr};
std::unique_ptr<tf2_ros::Buffer> tf_buffer_;
if (mode == "p95") {
compare_p95_buffers(buffer0, buffer1);
}
}

//port pod to starboard pod transform
geometry_msgs::msg::Transform portToStarboardTransform;
rclcpp::TimerBase::SharedPtr portToStarboardTransformTimer {nullptr};
rclcpp::Subscription<std_msgs::msg::Float32>::SharedPtr ampSubscription;
rclcpp::Publisher<std_msgs::msg::Bool>::SharedPtr resultPublisher;
rclcpp::TimerBase::SharedPtr resultTimer;
rclcpp::Service<std_srvs::srv::Trigger>::SharedPtr startSampleService;
rclcpp::Service<std_srvs::srv::Trigger>::SharedPtr stopSampleService;

// amplitude samples for the two comparison windows
std::vector<float> buffers[2];
int activeBuffer = 0;
bool sampling = false;

// last comparison result, invalid until the first compare completes
bool buffer0Closer = false;
bool haveResult = false;
bool did_fallback_on_max = false;
// the results of the comparison run on the buffers
float result_0 = 0.0f;
float result_1 = 0.0f;

};


int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalSubscriber>());
rclcpp::spin(std::make_shared<Acoustics>());
rclcpp::shutdown();
return 0;
}
}
Loading