-
Notifications
You must be signed in to change notification settings - Fork 0
Offline run #2
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
base: cam-streams
Are you sure you want to change the base?
Offline run #2
Changes from 6 commits
26a2dbd
294f53b
8b47941
bec79dd
bb7897c
9e918ff
ee1a2cc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,22 @@ | |
| extern "C" { | ||
| #endif | ||
|
|
||
| // Make dummy available to other files in namespace | ||
| // change so all files use getter func? | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are internal state variables. They shouldn't go in an externally-facing file. |
||
| namespace SOb { | ||
| extern bool dummy; | ||
| extern int taken_from_dummy; | ||
| extern bool going_up; | ||
| } | ||
|
|
||
| // Make avaiable to integ-test | ||
screechingviolet marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| UNITY_INTERFACE_EXPORT | ||
| bool UNITY_INTERFACE_API getDummy(); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use a more descriptive name (and make it follow the naming convention of external-facing APIs) |
||
| UNITY_INTERFACE_EXPORT | ||
| void UNITY_INTERFACE_API setDummy(bool val); | ||
|
|
||
|
|
||
| // Define a function pointer type for logging | ||
| typedef void (*SOb_LogCallback)(const char* message); | ||
|
|
||
|
|
@@ -28,6 +44,7 @@ enum SpotCamera { | |
| NUM_CAMERAS = 0x40, | ||
| }; | ||
|
|
||
|
|
||
| // Unity Stuff | ||
| void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unity); | ||
| void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -135,6 +135,7 @@ bool ReaderWriterCBuf::initialize( | |
| * Push image data to queue (non-blocking, drops oldest if full) | ||
| */ | ||
| void ReaderWriterCBuf::push(const google::protobuf::RepeatedPtrField<bosdyn::api::ImageResponse>& responses) { | ||
| // std::cout << "Dummy: " << (dummy ? "true" : "false") << std::endl; | ||
| using namespace std::chrono; | ||
|
|
||
| if (n_elems_per_rgb_ == 0 || n_elems_per_depth_ == 0) { | ||
|
|
@@ -159,6 +160,144 @@ void ReaderWriterCBuf::push(const google::protobuf::RepeatedPtrField<bosdyn::api | |
| int32_t n_rgbs_written = 0; | ||
| int32_t n_depths_written = 0; | ||
|
|
||
| if (dummy) { | ||
| for (int i = 0; i < 2; i++) { | ||
| if (going_up && taken_from_dummy >= 100) { | ||
| taken_from_dummy = 97; | ||
| going_up = false; | ||
| LogMessage("Dummy mode: reset taken_from_dummy counter"); | ||
| } else if (!going_up && taken_from_dummy <= 0) { | ||
| taken_from_dummy = 2; | ||
| going_up = true; | ||
| LogMessage("Dummy mode: reset taken_from_dummy counter"); | ||
| } | ||
|
|
||
| cv::Mat cv_img = cv::imread(std::format("..\\..\\saved_images\\spot_rgb{}.png", 1 + (taken_from_dummy/2)), cv::IMREAD_UNCHANGED); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will break if the code isn't launched from the right place |
||
| cv::cvtColor(cv_img, cv_img, cv::COLOR_BGR2RGB); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use cvtColor(img_rgba, cv2.COLOR_BGR2BGRA) instead of manually appending an alpha channel |
||
|
|
||
| std::vector<cv::Mat> channels; | ||
| cv::split(cv_img, channels); | ||
|
|
||
| // Create an alpha channel initialized to 255 (fully opaque) | ||
| cv::Mat alpha_channel = cv::Mat::ones(cv_img.size(), CV_8U) * 255; | ||
|
|
||
| // Add the alpha channel to the vector of channels | ||
| channels.push_back(alpha_channel); | ||
|
|
||
| // Merge the channels to create a BGRA image | ||
| cv::merge(channels, cv_img); | ||
| LogMessage("Dummy mode: read image with size {}x{} and {} channels", | ||
| cv_img.cols, cv_img.rows, cv_img.channels()); | ||
|
|
||
| // this code can be decoupled from our friend spot so it doesnt need to be repeated | ||
| size_t image_size = cv_img.cols * cv_img.rows * 4;//(img.pixel_format() == bosdyn::api::Image::PIXEL_FORMAT_RGBA_U8 ? 4 : 3); | ||
| if (image_size != n_elems_per_rgb_) { | ||
| LogMessage("Image size mismatch: expected {}, got {}", n_elems_per_rgb_, image_size); | ||
| throw std::runtime_error("ReaderWriterCBuf::push: Image size mismatch"); | ||
| } | ||
|
|
||
| // See if we need to do any cam-specific preprocessing: | ||
| switch (cameras_[n_rgbs_written]) { | ||
| case SpotCamera::FRONTLEFT: | ||
| case SpotCamera::FRONTRIGHT: | ||
| break; | ||
| } | ||
|
|
||
| LogMessage("Copying RGB image to CUDA"); | ||
| checkCudaError( | ||
| cudaMemcpyAsync( | ||
| rgb_write_ptr, | ||
| cv_img.data, | ||
| image_size * sizeof(uint8_t), | ||
| cudaMemcpyHostToDevice, | ||
| cuda_stream_ /* use per-connection stream */ | ||
| ), | ||
| "cudaMemcpyAsync RGB" | ||
| ); | ||
| LogMessage("Finished copying RGB image to CUDA"); | ||
|
|
||
| rgb_write_ptr += n_elems_per_rgb_; | ||
| n_rgbs_written++; | ||
|
|
||
| // if (going_up) taken_from_dummy++; | ||
| // else taken_from_dummy--; | ||
|
|
||
| // cv::Mat | ||
| cv_img = cv::imread(std::format("..\\..\\saved_images\\spot_depth{}.png", 1 + (taken_from_dummy/2)), cv::IMREAD_UNCHANGED); | ||
|
|
||
| // we multiplied depth by 255 when saving, so divide back here | ||
| cv_img.convertTo(cv_img, CV_32FC1, 1.0/255.0); | ||
|
|
||
| LogMessage("Dummy mode: read depth image with size {}x{}", | ||
| cv_img.cols, cv_img.rows); | ||
|
|
||
| int depth_width = cv_img.cols; | ||
| int depth_height = cv_img.rows; | ||
|
|
||
| size_t depth_size = depth_width * depth_height; | ||
| if (depth_size != n_elems_per_depth_) { | ||
| LogMessage("Depth size mismatch: expected {}, got {}", n_elems_per_depth_, depth_size); | ||
| throw std::runtime_error("ReaderWriterCBuf::push: Depth size mismatch"); | ||
| } | ||
|
|
||
| // LogMessage("Copying depth image of size {} bytes to write pointer at index {}, {:#x} rgb_write_ptr", | ||
| // depth_size, write_idx, size_t(depth_write_ptr)); | ||
|
|
||
| checkCudaError( | ||
| cudaMemcpyAsync( | ||
| depth_write_ptr, | ||
| cv_img.data, | ||
| depth_size * sizeof(float), | ||
| cudaMemcpyHostToDevice, | ||
| cuda_stream_ | ||
| ), | ||
| "cudaMemcpyAsync DEPTH" | ||
| ); | ||
|
|
||
| // If dumping requires device->host copies on default stream, this ensures correctness: | ||
| // checkCudaError(cudaStreamSynchronize(cuda_stream_), "sync before debug dump"); | ||
| DumpDepthImageFromCuda( | ||
| depth_write_ptr, | ||
| cv_img.cols, | ||
| cv_img.rows, | ||
| "pre-depth-cache", | ||
| n_depths_written + write_idx * n_images_per_response_ | ||
| ); | ||
|
|
||
| DumpDepthImageFromCuda( | ||
| depth_write_ptr, | ||
| cv_img.cols, | ||
| cv_img.rows, | ||
| "post-depth-cache", | ||
| n_depths_written + write_idx * n_images_per_response_ | ||
| ); | ||
|
|
||
| depth_write_ptr += n_elems_per_depth_; | ||
| depth_cache_ptr += n_elems_per_depth_; | ||
| n_depths_written++; | ||
|
|
||
| checkCudaError(cudaStreamSynchronize(cuda_stream_), "cudaStreamSynchronize after push"); | ||
|
|
||
| // Update indices/flags | ||
| assert(n_rgbs_written == n_depths_written); | ||
| // Update the read index to the write index we just wrote to. | ||
| read_idx_.store(write_idx, std::memory_order_release); | ||
| new_data_.store(true, std::memory_order_release); | ||
| LogMessage("ReaderWriterCBuf::push: updating write index from {} to {}", | ||
| write_idx, (write_idx + 1) % max_size_); | ||
| write_idx = (write_idx + 1) % max_size_; | ||
| write_idx_.store(write_idx, std::memory_order_release); | ||
| first_run_ = false; | ||
|
|
||
| if (going_up) taken_from_dummy+=2; | ||
| else taken_from_dummy-=2; | ||
|
|
||
| } | ||
| return; | ||
|
|
||
|
|
||
| } | ||
|
|
||
| for (const auto& response : responses) { | ||
| const auto& img = response.shot().image(); | ||
|
|
||
|
|
@@ -411,6 +550,10 @@ bosdyn::api::GetImageRequest SpotCamStream::_createImageRequest( | |
|
|
||
| void SpotCamStream::_startStreamingThread() { | ||
| // Create and start thread | ||
| if (!image_client_ && !dummy) { | ||
| std::cerr << "Image client not initialized" << std::endl; | ||
| return; | ||
| } | ||
| image_streamer_thread_ = std::make_unique<std::jthread>([this](std::stop_token stop_token) { | ||
| _spotCamReaderThread(stop_token); | ||
| }); | ||
|
|
@@ -424,6 +567,14 @@ void SpotCamStream::_spotCamReaderThread(std::stop_token stop_token) { | |
| try { | ||
| auto start = std::chrono::high_resolution_clock::now(); | ||
|
|
||
| if (dummy) { | ||
| google::protobuf::RepeatedPtrField<bosdyn::api::ImageResponse> dummy_responses; | ||
| image_lifo_.push(dummy_responses); | ||
| LogMessage("Dummy mode: pushed dummy image responses"); | ||
| std::this_thread::sleep_for(std::chrono::milliseconds(100)); | ||
| continue; | ||
| } | ||
|
|
||
| // Request images from all cameras | ||
| bosdyn::client::GetImageResultType response = image_client_->GetImage(current_request_); | ||
| if (!response.status) { | ||
|
|
@@ -493,13 +644,51 @@ bool SpotCamStream::streamCameras(uint32_t cam_mask) { | |
|
|
||
| num_cams_requested = rgb_sources.size(); | ||
|
|
||
| current_request_ = _createImageRequest(rgb_sources, depth_sources); | ||
| if (!dummy) current_request_ = _createImageRequest(rgb_sources, depth_sources); | ||
| if (image_streamer_thread_ != nullptr) { | ||
| _joinStreamingThread(); | ||
| } | ||
| } | ||
|
|
||
| try { | ||
| // AATASK: rewrite this part to give needed info from disk images | ||
| if (dummy) { | ||
| cv::Mat image = cv::imread(std::format("..\\..\\saved_images\\spot_rgb{}.png", 1), cv::IMREAD_COLOR); | ||
| cv::Size ref_size = image.size(); | ||
| // Check if the image was loaded successfully | ||
| if (image.empty()) { | ||
| std::cerr << "Error: Could not open or find the image at " << std::format("..\\..\\saved_images\\spot_rgb{}.png", 1) << std::endl; | ||
| return false; // Indicate an error | ||
| } | ||
|
|
||
| current_rgb_shape_ = TensorShape{ | ||
| size_t(num_cams_requested), | ||
| 4, //(image_responses[0].shot().image().pixel_format() == bosdyn::api::Image::PIXEL_FORMAT_RGBA_U8 ? 4 : 3) | ||
| size_t(ref_size.height), | ||
| size_t(ref_size.width) | ||
| }; | ||
|
|
||
| current_depth_shape_ = TensorShape{ | ||
| size_t(num_cams_requested), | ||
| 1, | ||
| size_t(ref_size.height), | ||
| size_t(ref_size.width) | ||
| }; | ||
|
|
||
| image_lifo_.initialize( | ||
| ref_size.width * ref_size.height * 4, // RGBA | ||
| ref_size.width * ref_size.height, // Depth | ||
| camera_order_ | ||
| ); | ||
|
|
||
| _startStreamingThread(); | ||
| streaming_ = true; | ||
| current_cam_mask_ = cam_mask; | ||
| current_num_cams_ = num_cams_requested; | ||
| return true; | ||
|
|
||
|
|
||
| } | ||
| constexpr int32_t max_connection_retries = 3; | ||
| // Query the robot for images and fill in image metadata | ||
| // Max 3 retries | ||
|
|
@@ -558,6 +747,7 @@ bool SpotCamStream::streamCameras(uint32_t cam_mask) { | |
| return false; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| // (Re)initialize circular buffer | ||
| image_lifo_.initialize( | ||
|
|
@@ -621,6 +811,13 @@ SpotConnection::SpotConnection( | |
| } | ||
|
|
||
| try { | ||
| if (dummy) { | ||
| LogMessage("SpotConnection::connect: Dummy mode enabled, skipping actual connection"); | ||
| connected_ = true; | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| // Create robot using ClientSDK | ||
| bosdyn::client::Result<std::unique_ptr<bosdyn::client::Robot>> robot_result = sdk_->CreateRobot(robot_ip); | ||
| if (!robot_result.status) { | ||
|
|
@@ -736,6 +933,7 @@ SpotCamStream* SpotConnection::getCamStream(int32_t stream_id) { | |
| } | ||
|
|
||
| bool SpotConnection::createVisionPipeline(MLModel& model, int32_t stream_id) { | ||
| LogMessage("SpotConnection::createVisionPipeline: Creating vision pipeline for stream ", stream_id); | ||
| SpotCamStream* cam_stream = getCamStream(stream_id); | ||
| if (cam_stream == nullptr || !cam_stream->isStreaming()) { | ||
| LogMessage("SpotConnection::createVisionPipeline: Camera stream {} doesn't exist. " | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert