Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions Gems/SensorDebug/Code/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ ly_add_target(
Gem::ImGui
Gem::ROS2.Static
Gem::ROS2.API
Gem::PhysX5.Static
)

# Here add ${gem_name} target, it depends on the Private Object library and Public API interface
Expand Down
189 changes: 186 additions & 3 deletions Gems/SensorDebug/Code/Source/Clients/SensorDebugSystemComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
#include <SensorDebug/SensorDebugTypeIds.h>

#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Components/ConsoleBus.h>

#include <AzCore/Time/ITime.h>
#include <PhysX/Configuration/PhysXConfiguration.h>

namespace SensorDebug
{
Expand All @@ -20,10 +24,13 @@ namespace SensorDebug
void SensorDebugSystemComponent::Activate()
{
ImGui::ImGuiUpdateListenerBus::Handler::BusConnect();
AZ::TickBus::Handler::BusConnect();
GetPhysXConfig();
}

void SensorDebugSystemComponent::Deactivate()
{
AZ::TickBus::Handler::BusDisconnect();
ImGui::ImGuiUpdateListenerBus::Handler::BusDisconnect();
}

Expand Down Expand Up @@ -96,6 +103,29 @@ namespace SensorDebug
AZ_Printf("TestComponent", "Found %d sensor entities", m_sensorEntities.size());
}

AzPhysics::Scene* SensorDebugSystemComponent::GetScene()
{
if (m_scene)
{
return m_scene;
}
AzPhysics::SystemInterface* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::Get();
AZ_Assert(physicsSystem, "No physics system.");

AzPhysics::SceneInterface* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get();
AZ_Assert(sceneInterface, "No scene intreface.");

AzPhysics::SceneHandle defaultSceneHandle = sceneInterface->GetSceneHandle(AzPhysics::DefaultPhysicsSceneName);
if (defaultSceneHandle == AzPhysics::InvalidSceneHandle)
{
return nullptr;
}
AzPhysics::Scene* scene = sceneInterface->GetScene(defaultSceneHandle);
AZ_Assert(defaultSceneHandle != AzPhysics::InvalidSceneHandle, "Invalid default physics scene pointer.");
m_scene = scene;
return scene;
}

void SensorDebugSystemComponent::FindSensorsWithGivenType(const char* typeId)
{
ClearSensors();
Expand Down Expand Up @@ -126,9 +156,118 @@ namespace SensorDebug
AZ_Printf("TestComponent", "Found %d sensor entities", m_sensorEntities.size());
}

void SensorDebugSystemComponent::Pause(bool isPaused)
{
GetScene()->SetEnabled(!isPaused);
}

void SensorDebugSystemComponent::UpdatePhysXConfig()
{
AzPhysics::SystemInterface* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::Get();
AZ_Assert(physicsSystem, "No physics system.");
auto* physicsSystemConfigurationPtr = physicsSystem->GetConfiguration();
auto* physicsSystemConfiguration = azdynamic_cast<const PhysX::PhysXSystemConfiguration*>(physicsSystemConfigurationPtr);
AZ_Assert(physicsSystemConfiguration, "Invalid physics system configuration pointer, a new Physics system in O3DE????");
physicsSystem->UpdateConfiguration(&m_modifiedPhysXConfig, true);
}

void SensorDebugSystemComponent::GetPhysXConfig()
{
AzPhysics::SystemInterface* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::Get();
AZ_Assert(physicsSystem, "No physics system.");
auto* physicsSystemConfigurationPtr = physicsSystem->GetConfiguration();
auto* physicsSystemConfiguration = azdynamic_cast<const PhysX::PhysXSystemConfiguration*>(physicsSystemConfigurationPtr);
AZ_Assert(physicsSystemConfiguration, "Invalid physics system configuration pointer, a new Physics system in O3DE????");
m_modifiedPhysXConfig = *physicsSystemConfiguration;
}

AZStd::string GetSecondAnimation(double value)
{
double part = value - AZStd::floor(value);
size_t numStars = static_cast<size_t>(part * 60);

AZStd::string anim (61, ' ');
numStars = AZStd::min(numStars, anim.length());
for (size_t i = 0; i <numStars; i++)
{
anim[i] = '*';
}
return anim;
}
void SensorDebugSystemComponent::OnImGuiUpdate()
{
ImGui::Begin("ROS2 SensorDebugger");
ImGui::Separator();
ImGui::Text("TimeyWimey Stuff");
const auto ros2Intreface = ROS2::ROS2Interface::Get();
auto ros2ts = ros2Intreface ? ROS2::ROS2Interface::Get()->GetROSTimestamp() : builtin_interfaces::msg::Time();
const float ros2tsSec = ros2ts.sec + ros2ts.nanosec / 1e9;
auto ros2Node = ros2Intreface ? ROS2::ROS2Interface::Get()->GetNode() : nullptr;
auto nodeTime = ros2Node ? ros2Node->now() : rclcpp::Time(0, 0);
const double ros2nodetsSec = nodeTime.seconds() + nodeTime.nanoseconds() / 1e9;

auto timeSystem = AZ::Interface<AZ::ITime>::Get();
const auto elapsedTime = timeSystem ? static_cast<double>(timeSystem->GetElapsedTimeUs()) / 1e6 : 0.0;

ImGui::Text("Current ROS 2 time (Gem) : %f %s", ros2tsSec, GetSecondAnimation(ros2tsSec).c_str());
ImGui::Text("Current ROS 2 time (Node) : %f %s", ros2nodetsSec, GetSecondAnimation(ros2nodetsSec).c_str());
ImGui::Text("Current O3DE time : %f %s", elapsedTime, GetSecondAnimation(elapsedTime).c_str());

ImGui::Separator();
ImGui::Text("PhysX");
ImGui::InputFloat("Fixed timestamp", &m_modifiedPhysXConfig.m_fixedTimestep, 0.0f, 0.0f, "%.6f");
ImGui::InputFloat("Max timestamp", &m_modifiedPhysXConfig.m_maxTimestep, 0.0f, 0.0f, "%.6f");
if (ImGui::Button("Update PhysX Config"))
{
UpdatePhysXConfig();
}
ImGui::SameLine();
if (ImGui::Button("Pause"))
{
Pause(true);
}
ImGui::SameLine();
if (ImGui::Button("Unpause"))
{
Pause(false);
}
ImGui::Separator();
ImGui::Text("Atom");

ImGui::InputFloat("Application Max FPS", &m_maxFPS);
ImGui::SameLine();
if (ImGui::Button("Set sys_MaxFPS"))
{
// disable vsync
AZStd::string commandVsync = AZStd::string::format("vsync_interval=0");
AzFramework::ConsoleRequestBus::Broadcast(&AzFramework::ConsoleRequests::ExecuteConsoleCommand, commandVsync.c_str());
AZStd::string commandMaxFps = AZStd::string::format("sys_MaxFPS=%f", m_maxFPS);
AzFramework::ConsoleRequestBus::Broadcast(&AzFramework::ConsoleRequests::ExecuteConsoleCommand, commandMaxFps.c_str());
m_appFrequencies.clear();
}

float freqencySum = 0.0f;
for (const auto& freq : m_appFrequencies)
{
freqencySum += freq;
}
const float averageFrequency = freqencySum / static_cast<float>(m_appFrequencies.size());
// compute std deviation
float variance = 0.0f;
for (const auto& freq : m_appFrequencies)
{
variance += (freq - averageFrequency) * (freq - averageFrequency);
}
float stdDeviation = sqrt(variance / static_cast<float>(m_appFrequencies.size()));
ImGui::Separator();
ImGui::PlotHistogram("App Actual Frequency", m_appFrequencies.data(), static_cast<int>(m_appFrequencies.size()), 0);
ImGui::Text("App Actual Frequency: %.2f Hz [ std_dev = %.2f ]", averageFrequency, stdDeviation);
ImGui::SameLine();
if (ImGui::Button("reset stats"))
{
m_appFrequencies.clear();
}
ImGui::Separator();
if (ImGui::Button("Refresh with EnumerateHandlers(o3de bus API)"))
{
FindSensorsWithBusAPI();
Expand Down Expand Up @@ -178,7 +317,7 @@ namespace SensorDebug
{
FindSensorsWithGivenType(ROS2::ROS2OdometrySensorComponent);
}

ImGui::InputInt("History Size", &m_historySize);
for (auto& sensorEntity : m_sensorEntities)
{
ImGui::Separator();
Expand All @@ -189,7 +328,42 @@ namespace SensorDebug
float frequency = 0.0f;
ROS2::SensorConfigurationRequestBus::EventResult(
frequency, sensorEntity, &ROS2::SensorConfigurationRequest::GetEffectiveFrequency);
ImGui::Text("%s : %s effective Freq: %f Hz", entityName.c_str(), sensorName.c_str(), frequency);

m_sensorFrequencyHistory[sensorEntity].push_back(frequency);
auto& sensorFrequencyHistory = m_sensorFrequencyHistory[sensorEntity];
if (sensorFrequencyHistory.size() > m_historySize)
{
sensorFrequencyHistory.erase(sensorFrequencyHistory.begin());
}
float freqencySum = 0.0f;
for (const auto& freq : sensorFrequencyHistory)
{
freqencySum += freq;
}
const float averageFrequency = freqencySum / static_cast<float>(sensorFrequencyHistory.size());
// compute std deviation
float variance = 0.0f;
for (const auto& freq : sensorFrequencyHistory)
{
variance += (freq - averageFrequency) * (freq - averageFrequency);
}
float stdDeviation = sqrt(variance / static_cast<float>(sensorFrequencyHistory.size()));
const AZStd::string histogramNameWithCookie = AZStd::string::format("Histogram%s", cookie.c_str());

ImGui::PlotHistogram(
histogramNameWithCookie.c_str(), sensorFrequencyHistory.data(), static_cast<int>(sensorFrequencyHistory.size()), 0);
ImGui::SameLine();
const AZStd::string resetButton = AZStd::string::format("reset stats%s", cookie.c_str());
if (ImGui::Button(resetButton.c_str()))
{
sensorFrequencyHistory.clear();
}
ImGui::Text(
"%s : %s effective Freq: %.2f Hz [ std_dev = %.2f ]",
entityName.c_str(),
sensorName.c_str(),
averageFrequency,
stdDeviation);

AZStd::string buttonNameEna = AZStd::string::format("Enable%s", cookie.c_str());
AZStd::string buttonNameDis = AZStd::string::format("Disable%s", cookie.c_str());
Expand Down Expand Up @@ -230,7 +404,7 @@ namespace SensorDebug
ROS2::SensorConfigurationRequestBus::Event(sensorEntity, &ROS2::SensorConfigurationRequest::SetVisualizeEnabled, false);
}
AZStd::string freqName = AZStd::string::format("Frequency%s", cookie.c_str());
ImGui::DragFloat(freqName.c_str(), &m_sensorFrequencies[sensorEntity], 0.1f, 0.1f, 500.0f);
ImGui::InputFloat(freqName.c_str(), &m_sensorFrequencies[sensorEntity]);
ImGui::SameLine();
AZStd::string buttonSetFreq = AZStd::string::format("Set Frequency%s", cookie.c_str());
if (ImGui::Button(buttonSetFreq.c_str()))
Expand All @@ -242,4 +416,13 @@ namespace SensorDebug

ImGui::End();
}

void SensorDebugSystemComponent::OnTick(float deltaTime, AZ::ScriptTimePoint time)
{
m_appFrequencies.push_back(1.0f / deltaTime);
if (m_appFrequencies.size() > m_historySize)
{
m_appFrequencies.erase(m_appFrequencies.begin());
}
}
} // namespace SensorDebug
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,24 @@
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TickBus.h>

#include <AzCore/Component/TickBus.h>
#include <AzFramework/Physics/PhysicsSystem.h>
#include <ImGuiBus.h>
#include <PhysX/Configuration/PhysXConfiguration.h>
#include <ROS2/Sensor/Events/TickBasedSource.h>
#include <ROS2/Sensor/ROS2SensorComponentBase.h>
#include <ROS2/Sensor/SensorConfigurationRequestBus.h>
#include <ROS2/Sensor/SensorHelper.h>
#include <imgui/imgui.h>

namespace SensorDebug
{


class SensorDebugSystemComponent
: public AZ::Component
, public ImGui::ImGuiUpdateListenerBus::Handler
, private AZ::TickBus::Handler
{
public:
AZ_COMPONENT_DECL(SensorDebugSystemComponent);
Expand All @@ -35,12 +42,26 @@ namespace SensorDebug
void ClearSensors();

private:
// AZ::TickBus::Handler interface implementation
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;

void UpdatePhysXConfig();
void GetPhysXConfig();
void Pause(bool isPaused);
AzPhysics::Scene* GetScene();

void FindSensorsWithBusAPI();
void FindSensorsWithComponentAPI();
void FindSensorsWithGivenType(const char* typeId);
AZStd::vector<AZ::EntityComponentIdPair> m_sensorEntities;
AZStd::unordered_map<AZ::EntityComponentIdPair, AZStd::vector<float>> m_sensorFrequencyHistory;
AZStd::unordered_map<AZ::EntityComponentIdPair, AZStd::string> m_sensorNames;
AZStd::unordered_map<AZ::EntityComponentIdPair, AZStd::string> m_entitiesNames;
AZStd::unordered_map<AZ::EntityComponentIdPair, float> m_sensorFrequencies;
AZStd::vector<float> m_appFrequencies;
float m_maxFPS = 60.0f;
int m_historySize = 1000;
AzPhysics::Scene* m_scene = nullptr;
PhysX::PhysXSystemConfiguration m_modifiedPhysXConfig;
};
} // namespace SensorDebug
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,25 @@ namespace SensorDebug

void SensorDebugEditorSystemComponent::Activate()
{
SensorDebugSystemComponent::Activate();

AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect();
}

void SensorDebugEditorSystemComponent::Deactivate()
{
AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect();
SensorDebugSystemComponent::Deactivate();

}

void SensorDebugEditorSystemComponent::OnStartPlayInEditorBegin()
{
ClearSensors();
SensorDebugSystemComponent::Activate();
}

void SensorDebugEditorSystemComponent::OnStopPlayInEditor()
{
ClearSensors();
SensorDebugSystemComponent::Deactivate();
}
} // namespace SensorDebug
Loading