Skip to content

Commit 224a0e3

Browse files
authored
Merge pull request #280 from tritonuas/feat/use-not-stolen-as-mock-camera
2 parents 0ba70ab + b97ccec commit 224a0e3

File tree

7 files changed

+80
-58
lines changed

7 files changed

+80
-58
lines changed

configs/dev.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,16 @@
5454
"cv": {
5555
"yolo_model_dir": "/workspaces/obcpp/models/yolo11x.onnx",
5656
"not_stolen_addr": "localhost",
57-
"not_stolen_port": 5069
57+
"not_stolen_port": 6060
5858
},
5959
"camera": {
6060
"_comment": "See CameraConfig struct in datatypes.hpp for detailed explanations",
6161
"type": "mock",
62-
"save_dir": "/workspaces/obcpp/images/",
63-
"save_images_to_file": false,
62+
"save_dir": "/workspaces/obcpp/images/mock",
63+
"save_images_to_file": true,
6464
"mock": {
65-
"images_dir": "/workspaces/obcpp/images/mock/"
65+
"not_stolen_port": 6060,
66+
"num_images": 10
6667
},
6768
"lucid": {
6869
"sensor_shutter_mode": "Rolling",

configs/jetson.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,16 @@
5454
"cv": {
5555
"yolo_model_dir": "/obcpp/models/yolo11x.onnx",
5656
"not_stolen_addr": "localhost",
57-
"not_stolen_port": 5069
57+
"not_stolen_port": 6060
5858
},
5959
"camera": {
6060
"_comment": "See CameraConfig struct in datatypes.hpp for detailed explanations",
6161
"type": "picamera",
6262
"save_dir": "/obcpp/images/",
6363
"save_images_to_file": true,
6464
"mock": {
65-
"images_dir": "/obcpp/tests/integration/images/saliency/"
65+
"not_stolen_port": 6060,
66+
"num_images": 10
6667
},
6768
"lucid": {
6869
"sensor_shutter_mode": "Rolling",

docker/sitl-compose.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ services:
99
not-stolen-israeli-code:
1010
image: ghcr.io/tritonuas/not-stolen-israeli-code:latest
1111
volumes:
12-
- ~/dev/tritonuas/not-stolen-israeli-code/backgrounds:/not-stolen-israeli-code/backgrounds
13-
- ~/dev/tritonuas/not-stolen-israeli-code/emergent_target_pics:/not-stolen-israeli-code/emergent_target_pics
12+
- ~/Clubs/TUAS/not-stolen-israeli-code/backgrounds:/not-stolen-israeli-code/backgrounds
13+
- ~/Clubs/TUAS/not-stolen-israeli-code/emergent_target_pics:/not-stolen-israeli-code/emergent_target_pics
1414
ports:
15-
- 5069:5000
15+
- 5069:6060
16+
command: poetry run python main.py -d
1617
volumes:
1718
sitl:

include/camera/mock.hpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <deque>
88
#include <vector>
99
#include <filesystem>
10+
#include <string>
1011

1112
#include "camera/interface.hpp"
1213
#include "network/mavlink.hpp"
@@ -63,10 +64,7 @@ class MockCamera : public CameraInterface {
6364

6465
std::thread captureThread;
6566

66-
// Get telemetry from JSON file adjacent to given image file.
67-
// Ex: given path to "0003.jpg", telemetry will be looked for in
68-
// "0003.json"
69-
std::optional<ImageTelemetry> getTelemetryFromJsonFile(std::filesystem::path img_path);
67+
std::optional<ImageTelemetry> getTelemetryFromJsonResponse(std::string server_response);
7068
};
7169

7270
#endif // INCLUDE_CAMERA_MOCK_HPP_

include/utilities/obc_config.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,10 @@ struct CameraConfig {
116116
// whether or not to save to save_dir
117117
bool save_images_to_file;
118118
struct {
119-
// directory to randomly pick images from
120-
// for the mock camera
121-
std::string images_dir;
119+
// port to query images from for the mock camera
120+
int not_stolen_port;
121+
// number of images to pull
122+
int num_images;
122123
} mock;
123124
};
124125

src/camera/mock.cpp

Lines changed: 60 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "camera/mock.hpp"
22

3+
#include <httplib.h>
4+
35
#include <chrono>
46
#include <thread>
57
#include <optional>
@@ -13,25 +15,46 @@
1315
#include "utilities/locks.hpp"
1416
#include "utilities/rng.hpp"
1517
#include "utilities/common.hpp"
18+
#include "utilities/base64.hpp"
1619

1720

1821
MockCamera::MockCamera(CameraConfig config) : CameraInterface(config) {
19-
std::ranges::for_each(
20-
std::filesystem::directory_iterator{this->config.mock.images_dir},
21-
[this](const auto& dir_entry) {
22-
cv::Mat img = cv::imread(dir_entry.path().string());
23-
// if the image is read
24-
if (img.data != NULL) {
25-
std::optional<ImageTelemetry> telemetry =
26-
this->getTelemetryFromJsonFile(dir_entry.path());
27-
28-
ImageData img_data(
29-
img,
30-
0,
31-
telemetry);
32-
this->mock_images.push_back(img_data);
33-
}
34-
});
22+
LOG_F(INFO, "Grabbing images from port " + config.mock.not_stolen_port);
23+
httplib::Client cli("localhost", config.mock.not_stolen_port);
24+
25+
cli.set_read_timeout(10);
26+
27+
for (int i = 0; i < config.mock.num_images; i++) {
28+
httplib::Result res = cli.Get("/generate?format=json");
29+
30+
if (!res || res->status != 200) {
31+
LOG_F(ERROR, "Failed to query server for images");
32+
continue;
33+
}
34+
35+
nlohmann::json json = nlohmann::json::parse(res->body, nullptr, true, true);
36+
37+
std::string decoded_img = base64_decode(json["image_base64"]);
38+
std::vector<uchar> data(decoded_img.begin(), decoded_img.end());
39+
40+
cv::Mat img = cv::imdecode(data, cv::IMREAD_COLOR);
41+
42+
if (img.data == NULL) {
43+
LOG_F(ERROR, "Failed to decode image from server response");
44+
continue;
45+
}
46+
47+
ImageTelemetry telemetry = this->getTelemetryFromJsonResponse(res->body).value();
48+
49+
ImageData img_data(
50+
img,
51+
0,
52+
telemetry);
53+
54+
this->mock_images.push_back(img_data);
55+
}
56+
57+
cli.stop();
3558
}
3659

3760
MockCamera::~MockCamera() {
@@ -43,11 +66,12 @@ void MockCamera::connect() { return; }
4366
bool MockCamera::isConnected() { return true; }
4467

4568
void MockCamera::startTakingPictures(const std::chrono::milliseconds& interval,
46-
std::shared_ptr<MavlinkClient> mavlinkClient) {
69+
std::shared_ptr<MavlinkClient> mavlinkClient) {
4770
this->isTakingPictures = true;
4871
try {
4972
this->captureThread = std::thread(&MockCamera::captureEvery, this, interval, mavlinkClient);
50-
} catch (const std::exception& e) {
73+
}
74+
catch (const std::exception& e) {
5175
std::cerr << e.what() << std::endl;
5276
}
5377
}
@@ -77,11 +101,11 @@ std::deque<ImageData> MockCamera::getAllImages() {
77101
}
78102

79103
void MockCamera::captureEvery(const std::chrono::milliseconds& interval,
80-
std::shared_ptr<MavlinkClient> mavlinkClient) {
104+
std::shared_ptr<MavlinkClient> mavlinkClient) {
81105
loguru::set_thread_name("mock camera");
82106
while (this->isTakingPictures) {
83-
LOG_F(INFO, "Taking picture with mock camera. Using images from %s",
84-
this->config.mock.images_dir.c_str());
107+
LOG_F(INFO, "Taking picture with mock camera. Using images from port %d",
108+
this->config.mock.not_stolen_port);
85109
auto imageData = this->takePicture(interval, mavlinkClient);
86110

87111
if (!imageData.has_value()) {
@@ -98,8 +122,8 @@ void MockCamera::captureEvery(const std::chrono::milliseconds& interval,
98122
}
99123

100124
std::optional<ImageData> MockCamera::takePicture(const std::chrono::milliseconds& timeout,
101-
std::shared_ptr<MavlinkClient> mavlinkClient) {
102-
int random_idx = randomInt(0, this->mock_images.size()-1);
125+
std::shared_ptr<MavlinkClient> mavlinkClient) {
126+
int random_idx = randomInt(0, this->mock_images.size() - 1);
103127

104128
ImageData img_data = this->mock_images.at(random_idx);
105129
uint64_t timestamp = getUnixTime_s().count();
@@ -110,7 +134,7 @@ std::optional<ImageData> MockCamera::takePicture(const std::chrono::milliseconds
110134
img_data.TELEMETRY = queryMavlinkImageTelemetry(mavlinkClient);
111135
}
112136

113-
ImageData imageData {
137+
ImageData imageData{
114138
.DATA = img_data.DATA,
115139
.TIMESTAMP = timestamp,
116140
.TELEMETRY = img_data.TELEMETRY,
@@ -121,22 +145,17 @@ std::optional<ImageData> MockCamera::takePicture(const std::chrono::milliseconds
121145

122146
void MockCamera::startStreaming() {}
123147

124-
std::optional<ImageTelemetry> MockCamera::getTelemetryFromJsonFile(std::filesystem::path img_path) {
125-
img_path.replace_extension("json");
126-
std::ifstream telemetry_stream(img_path);
127-
if (!telemetry_stream.is_open()) {
128-
// no corresponding telemetry json found
129-
return {};
130-
}
131-
nlohmann::json json = nlohmann::json::parse(telemetry_stream, nullptr, true, true);
132-
return ImageTelemetry {
133-
.latitude_deg = json["latitude_deg"],
134-
.longitude_deg = json["longitude_deg"],
135-
.altitude_agl_m = json["altitude_agl_m"],
136-
.airspeed_m_s = json["airspeed_m_s"],
137-
.heading_deg = json["heading_deg"],
138-
.yaw_deg = json["yaw_deg"],
139-
.pitch_deg = json["pitch_deg"],
140-
.roll_deg = json["roll_deg"],
148+
std::optional<ImageTelemetry> MockCamera::getTelemetryFromJsonResponse(std::string json_response) {
149+
nlohmann::json json = nlohmann::json::parse(json_response, nullptr, true, true);
150+
151+
return ImageTelemetry{
152+
.latitude_deg = json["background"]["lat"],
153+
.longitude_deg = json["background"]["lon"],
154+
.altitude_agl_m = json["altitude"],
155+
.airspeed_m_s = 0.0,
156+
.heading_deg = json["background"]["heading_deg"],
157+
.yaw_deg = 0.0,
158+
.pitch_deg = 0.0,
159+
.roll_deg = 0.0,
141160
};
142161
}

src/utilities/obc_config.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ OBCConfig::OBCConfig(int argc, char* argv[]) {
9393
SET_CONFIG_OPT(camera, type);
9494
SET_CONFIG_OPT(camera, save_dir);
9595
SET_CONFIG_OPT(camera, save_images_to_file);
96-
SET_CONFIG_OPT(camera, mock, images_dir);
96+
SET_CONFIG_OPT(camera, mock, not_stolen_port);
97+
SET_CONFIG_OPT(camera, mock, num_images);
9798

9899
SET_CONFIG_OPT(takeoff, altitude_m);
99100
SET_CONFIG_OPT(takeoff, payload_size);

0 commit comments

Comments
 (0)