Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SVO logging #37

Merged
merged 32 commits into from
Jan 31, 2025
Merged

SVO logging #37

merged 32 commits into from
Jan 31, 2025

Conversation

ds58
Copy link
Contributor

@ds58 ds58 commented Jan 13, 2025

No description provided.

@ds58 ds58 changed the title [WIP] SVO logging SVO logging Jan 14, 2025
@ds58 ds58 marked this pull request as ready for review January 14, 2025 17:17

public class YoVariableLoggerDispatcher implements DataServerDiscoveryListener
{
private static final boolean ZED_SDK_LOADED = ZEDJavaAPINativeLibrary.load();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ZEDJavaAPINativeLibrary.load() only gets called once, it will return false if ZED SDK is not available on the system

Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this get called in the manager? That way we don't have to pass it all the way down.
I don't feel the user needs to be aware this is happening unless they go looking at the manager it self.

Copy link
Member

Choose a reason for hiding this comment

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

I was thinking that too when I first saw it

@@ -82,8 +91,7 @@ public void connected(HTTPDataServerConnection connection)
{
try
{
new YoVariableLogger(connection, options, (request) -> finishedLog(request));
activeLogSessions.add(hashAnnouncement);
activeLogSessions.put(hashAnnouncement, new YoVariableLogger(connection, options, this::finishedLog, ZED_SDK_LOADED));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We pass ZED_SDK_LOADED into YoVariableLogger so it knows if it should initialize ZEDSVOLoggerManager or not

@@ -39,7 +39,7 @@ mainDependencies {
api("us.ihmc:ihmc-video-codecs:2.1.6")
api("us.ihmc:ihmc-realtime:1.7.0")
api("us.ihmc:ihmc-java-decklink-capture:0.4.0")
api("us.ihmc:ihmc-pub-sub:1.1.5")
api("us.ihmc:ros2-library:1.1.5")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added because ZEDSVOLoggerManager uses a ROS2Node for subscribing to the ZEDSDKAnnounce topic.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We define the messages in the logger as IDL, not .msg

Copy link
Member

Choose a reason for hiding this comment

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

Seems you generated these and then copied them in. I think it would make sense to add the Gradle task to generate these, (maybe even start from .msg, just to be the same as everywhere else.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, I manually wrote this idl. I don't want to convert everything here to .msg, that is a lot more work and unnecessary

Copy link
Member

Choose a reason for hiding this comment

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

Oh I see there's an existing generation step.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep you use gradle generateMessages from the project root dir

@ds58
Copy link
Contributor Author

ds58 commented Jan 14, 2025

Example log directory output with multiple SVOs. A new SVO is created each time the ZED SDK is restarted on the robot.

d@d-desktop2:~/robotLogs/20250114_105240_ExampleServer$ tree .
.
├── handshake.yaml
├── perception
│   ├── 20250114_105242_ZEDRecording.svo2
│   ├── 20250114_105331_ZEDRecording.svo2
│   └── 20250114_105343_ZEDRecording.svo2
├── robotData.bsz
├── robotData.dat
└── robotData.log

1 directory, 7 files

@@ -119,7 +130,8 @@ private void finishedLog(Announcement request)
// Then remove this session from the list of active log sessions
ThreadTools.sleep(2000);
HashAnnouncement hashRequest = new HashAnnouncement(request);
activeLogSessions.remove(hashRequest);
YoVariableLogger logger = activeLogSessions.remove(hashRequest);
logger.destroy();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

YoVariableLogger has a destroy() now, which gets called when a log has finished

Comment on lines +63 to +66
Runtime.getRuntime().addShutdownHook(new Thread(() ->
{
activeLogSessions.forEach((hashAnnouncement, yoVariableLogger) -> yoVariableLogger.destroy());
}, getClass().getName() + "Shutdown"));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Calling YoVariableLogger#destroy() when the logger shuts down

Copy link
Collaborator

@PotatoPeeler3000 PotatoPeeler3000 left a comment

Choose a reason for hiding this comment

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

This is pretty awesome. I've got some concerns about the ZedSVOLoggerManager and the ZEDSVOLogger. Some stuff about threading, and is all of its necessary. Let me know what you think. Can also tag up in person if that helps explain things.


public class YoVariableLoggerDispatcher implements DataServerDiscoveryListener
{
private static final boolean ZED_SDK_LOADED = ZEDJavaAPINativeLibrary.load();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this get called in the manager? That way we don't have to pass it all the way down.
I don't feel the user needs to be aware this is happening unless they go looking at the manager it self.

{
ZEDSVOLogger zedSVOLogger = zedLoggers.get(announceHash);

if (zedSVOLogger.completelyStopped() && !zedSVOLogger.failedBeyondRecovery())
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need to do this? Why do we care about removing it from the list? The zed logger doesn't get stopped from what I can tell either.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is where I think we could check if things were stopped() rather then completelyStopped() and we could remove completely stopped. In general there shouldn't be a difference between stopped and completely stopped so I think we should only have one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We want to keep it around if it is failedBeyondRecovery() so that it doesnt try to reconnect, which may cause a native crash (crashing the logger)

/**
* @return true if ZED SDK has completely closed the camera and stop() has completely finished
*/
public boolean completelyStopped()
Copy link
Collaborator

Choose a reason for hiding this comment

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

The difference between stopped and completely stopped isn't clear. It doesn't make sense to have both. I think we could change this to just have the stopped() check, and we can check that in the manager as well if needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've renamed stopped() to stopRequested() so that it is more clear

grabThread.startRepeating();
}

connectionWatchdogThread.setFrequencyLimit(Conversions.secondsToHertz(CONNECT_TIMEOUT));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is it possible to remove the connectionWatchdogThread and check for a timeout within grabThread. Starting 2 threads in this class seems like too much.
The grabThread could have a different frequency. So its not unlimited, and we could have a counter that when it reaches a certain number it assumes a timeout. And each time we get a new frame, that timer gets reset. So its only ticking up when no frames are being received.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I haven't looked but do you know how the BlackMagicLogger times out after 5 seconds? We could pattern match that one. That may happen on the native side though I'm not sure. Starting 2 threads concerns me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The grabThread is unlimited frequency to avoid any delay or latency. The ZED SDK handles throttling the frequency because sl_grab() is blocking. This is the best way to do it.

I'd rather not put the timeout stuff in the grabThread because the logic would be more complicated.

Copy link
Contributor Author

@ds58 ds58 Jan 27, 2025

Choose a reason for hiding this comment

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

Starting 2 threads concerns me.

why?

}

public void grab()
{
Copy link
Collaborator

Choose a reason for hiding this comment

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

It the grab() method we should be checking if we can still grab a frame. So part of the connectionCheck() should happen in this method. That way we check if we can grab right before we attempt to grab a frame.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

connectionCheck has to be asynchronous, because grab() is blocking

@ds58 ds58 requested a review from PotatoPeeler3000 January 31, 2025 18:21
@ds58 ds58 merged commit c2258a5 into develop Jan 31, 2025
2 checks passed
@ds58 ds58 deleted the svo-logging branch January 31, 2025 21:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants