Skip to content

Commit 1993877

Browse files
committed
Merge branch 'master' into enhancement/load-config-for-server
2 parents c22d806 + 46e7fc8 commit 1993877

14 files changed

Lines changed: 176 additions & 87 deletions

CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ find_package(keisan REQUIRED)
2020
find_package(OpenCV REQUIRED)
2121
find_package(rclcpp REQUIRED)
2222
find_package(shisen_interfaces REQUIRED)
23+
find_package(jitsuyo REQUIRED)
2324
find_package(sensor_msgs REQUIRED)
2425
find_package(std_msgs REQUIRED)
2526
find_package(Protobuf CONFIG REQUIRED)
@@ -40,7 +41,7 @@ add_library(${PROJECT_NAME} SHARED
4041
"src/${PROJECT_NAME}/config/grpc/call_data_load_config.cpp"
4142
"src/${PROJECT_NAME}/config/grpc/call_data_save_capture_setting.cpp"
4243
"src/${PROJECT_NAME}/config/grpc/call_data_set_capture_setting.cpp"
43-
"src/${PROJECT_NAME}/config/utils/config.cpp"
44+
"src/${PROJECT_NAME}/config/grpc/call_data_record_image.cpp"
4445
"src/${PROJECT_NAME}/utility/capture_setting.cpp"
4546
"src/${PROJECT_NAME}/utility/interface.cpp"
4647
"src/${PROJECT_NAME}/node/shisen_cpp_node.cpp"
@@ -73,6 +74,7 @@ ament_target_dependencies(${PROJECT_NAME}
7374
OpenCV
7475
rclcpp
7576
shisen_interfaces
77+
jitsuyo
7678
sensor_msgs
7779
cv_bridge
7880
std_msgs
@@ -83,6 +85,7 @@ ament_target_dependencies(${PROJECT_NAME}_exported
8385
OpenCV
8486
rclcpp
8587
shisen_interfaces
88+
jitsuyo
8689
sensor_msgs
8790
cv_bridge
8891
std_msgs)
@@ -94,6 +97,10 @@ target_link_libraries(${PROJECT_NAME}
9497

9598
install(DIRECTORY "include" DESTINATION ".")
9699

100+
install(DIRECTORY
101+
launch
102+
DESTINATION "share/${PROJECT_NAME}")
103+
97104
install(TARGETS ${PROJECT_NAME}
98105
EXPORT export_${PROJECT_NAME}
99106
ARCHIVE DESTINATION "lib"

include/shisen_cpp/camera/node/camera_node.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class CameraNode
4343
void update();
4444
void on_mat_captured(cv::Mat mat);
4545
void on_camera_config(int width, int height);
46+
void save_image(cv::Mat mat);
4647
CaptureSetting on_configure_capture_setting(const CaptureSetting & capture_setting);
4748
void configure_capture_setting(const CaptureSetting & capture_setting = CaptureSetting());
4849
void load_configuration(const std::string & path);

include/shisen_cpp/config/utils/config.hpp renamed to include/shisen_cpp/config/grpc/call_data_record_image.hpp

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,28 @@
1818
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1919
// THE SOFTWARE.
2020

21-
#ifndef SHISEN_CPP__CONFIG__UTILS__CONFIG_HPP_
22-
#define SHISEN_CPP__CONFIG__UTILS__CONFIG_HPP_
21+
#ifndef SHISEN_CPP__CONFIG__GRPC__CALL_DATA_RECORD_IMAGE_HPP__
22+
#define SHISEN_CPP__CONFIG__GRPC__CALL_DATA_RECORD_IMAGE_HPP__
2323

24-
#include <nlohmann/json.hpp>
24+
#include <shisen_cpp/camera/node/camera_node.hpp>
25+
#include <shisen_cpp/config/grpc/call_data.hpp>
2526

2627
namespace shisen_cpp
2728
{
28-
29-
class Config
29+
class CallDataRecordImage
30+
: CallData<shisen_interfaces::proto::Empty, shisen_interfaces::proto::Empty>
3031
{
3132
public:
32-
explicit Config(const std::string & path);
33-
34-
std::string get_capture_setting(const std::string & key) const;
35-
void save_capture_setting(const nlohmann::json & capture_data);
36-
nlohmann::json get_grpc_config() const;
37-
38-
private:
39-
std::string path;
33+
CallDataRecordImage(
34+
shisen_interfaces::proto::Config::AsyncService * service, grpc::ServerCompletionQueue * cq,
35+
const std::string & path, const std::shared_ptr<camera::CameraNode>& camera_node);
36+
37+
protected:
38+
void AddNextToCompletionQueue() override;
39+
void WaitForRequest() override;
40+
void HandleRequest() override;
41+
std::shared_ptr<camera::CameraNode> camera_node_;
4042
};
41-
4243
} // namespace shisen_cpp
4344

44-
#endif // SHISEN_CPP__CONFIG__UTILS__CONFIG_HPP_
45+
#endif // SHISEN_CPP__CONFIG__GRPC__CALL_DATA_RECORD_IMAGE_HPP__

include/shisen_cpp/node/shisen_cpp_node.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#include <rclcpp/rclcpp.hpp>
2525
#include <shisen_cpp/camera/node/camera_node.hpp>
2626
#include <shisen_cpp/config/grpc/config.hpp>
27-
#include <shisen_cpp/config/utils/config.hpp>
2827
#include <shisen_cpp/utility.hpp>
2928

3029
#include <memory>

launch/shisen_cpp_launch.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright (c) 2024 ICHIRO ITS
2+
#
3+
# Permission is hereby granted, free of charge, to any person obtaining a copy
4+
# of this software and associated documentation files (the "Software"), to deal
5+
# in the Software without restriction, including without limitation the rights
6+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
# copies of the Software, and to permit persons to whom the Software is
8+
# furnished to do so, subject to the following conditions:
9+
#
10+
# The above copyright notice and this permission notice shall be included in
11+
# all copies or substantial portions of the Software.
12+
#
13+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16+
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
# THE SOFTWARE.
20+
21+
import os
22+
import socket
23+
from launch import LaunchDescription
24+
from launch_ros.actions import Node
25+
26+
def generate_launch_description():
27+
hostname = socket.gethostname()
28+
config_path = os.path.expanduser(f'~/ros2-ws/configuration/{hostname}/camera/')
29+
30+
return LaunchDescription([
31+
Node(
32+
package='shisen_cpp',
33+
executable='camera',
34+
name='camera',
35+
output='screen',
36+
arguments=[config_path],
37+
respawn=True,
38+
respawn_delay=1
39+
)
40+
])

package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<license>MIT License</license>
99
<buildtool_depend>ament_cmake</buildtool_depend>
1010
<depend>cv_bridge</depend>
11+
<depend>jitsuyo</depend>
1112
<depend>keisan</depend>
1213
<depend>libopencv-dev</depend>
1314
<depend>rclcpp</depend>

src/shisen_cpp/camera/node/camera_node.cpp

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,16 @@
1818
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1919
// THE SOFTWARE.
2020

21+
2122
#include <nlohmann/json.hpp>
23+
#include <opencv2/imgcodecs.hpp>
2224
#include <shisen_cpp/camera/node/camera_node.hpp>
25+
#include <jitsuyo/config.hpp>
2326

27+
#include <chrono>
2428
#include <fstream>
2529
#include <memory>
30+
#include <sstream>
2631
#include <string>
2732

2833
namespace shisen_cpp::camera
@@ -64,6 +69,32 @@ void CameraNode::on_camera_config(int width, int height)
6469
camera_config_publisher->publish(camera_config_provider->get_camera_config());
6570
}
6671

72+
void CameraNode::save_image(cv::Mat mat)
73+
{
74+
if (!std::filesystem::exists("image")) {
75+
if (!std::filesystem::create_directory("image")) {
76+
RCLCPP_ERROR(node->get_logger(), "Error creating `image` directory!");
77+
return;
78+
}
79+
}
80+
81+
auto now = std::chrono::system_clock::now();
82+
std::time_t now_time_t = std::chrono::system_clock::to_time_t(now);
83+
auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
84+
85+
std::stringstream ss;
86+
ss << std::put_time(std::localtime(&now_time_t), "%Y-%m-%d_%H-%M-%S");
87+
ss << '-' << std::setfill('0') << std::setw(3) << now_ms.count();
88+
std::string timestamp = ss.str();
89+
90+
std::string filename = "image/" + timestamp + ".jpg";
91+
92+
bool result = cv::imwrite(filename, mat);
93+
if (!result) {
94+
RCLCPP_ERROR(node->get_logger(), "Failed to save image!");
95+
}
96+
}
97+
6798
cv::Mat CameraNode::get_mat()
6899
{
69100
update();
@@ -161,12 +192,10 @@ CaptureSetting CameraNode::on_configure_capture_setting(
161192
}
162193

163194
if (new_capture_setting.temperature.is_not_empty()) {
164-
video_capture->set(cv::CAP_PROP_AUTO_WB, 0);
165195
video_capture->set(cv::CAP_PROP_WB_TEMPERATURE, new_capture_setting.temperature);
166196
}
167197

168198
if (new_capture_setting.exposure.is_not_empty()) {
169-
video_capture->set(cv::CAP_PROP_AUTO_EXPOSURE, 1);
170199
video_capture->set(cv::CAP_PROP_EXPOSURE, new_capture_setting.exposure);
171200
}
172201

@@ -195,38 +224,38 @@ void CameraNode::configure_capture_setting(const CaptureSetting & capture_settin
195224

196225
void CameraNode::load_configuration(const std::string & path)
197226
{
198-
std::string ss = path + "capture_settings.json";
199-
200-
std::ifstream input(ss, std::ifstream::in);
201-
if (!input.is_open()) {
202-
throw std::runtime_error("Unable to open `" + ss + "`!");
227+
nlohmann::json config;
228+
if (!jitsuyo::load_config(path, "capture_settings.json", config)) {
229+
throw std::runtime_error("Unable to open `" + path + "capture_settings.json`!");
203230
}
204231

205-
nlohmann::json config = nlohmann::json::parse(input);
206-
207232
CaptureSetting capture_setting;
208233

209-
// Get all config
210-
for (auto & item : config.items()) {
211-
try {
212-
if (item.key() == "brightness") {
213-
capture_setting.brightness.set(item.value());
214-
} else if (item.key() == "contrast") {
215-
capture_setting.contrast.set(item.value());
216-
} else if (item.key() == "saturation") {
217-
capture_setting.saturation.set(item.value());
218-
} else if (item.key() == "temperature") {
219-
capture_setting.temperature.set(item.value());
220-
} else if (item.key() == "exposure") {
221-
capture_setting.exposure.set(item.value());
222-
} else if (item.key() == "gain") {
223-
capture_setting.gain.set(item.value());
224-
}
225-
} catch (nlohmann::json::parse_error & ex) {
226-
throw std::runtime_error("Parse error at byte `" + std::to_string(ex.byte) + "`!");
227-
}
234+
int setting_brightness;
235+
int setting_contrast;
236+
int setting_saturation;
237+
int setting_temperature;
238+
int setting_exposure;
239+
int setting_gain;
240+
241+
if (!jitsuyo::assign_val(config, "brightness", setting_brightness) ||
242+
!jitsuyo::assign_val(config, "contrast", setting_contrast) ||
243+
!jitsuyo::assign_val(config, "saturation", setting_saturation) ||
244+
!jitsuyo::assign_val(config, "temperature", setting_temperature) ||
245+
!jitsuyo::assign_val(config, "exposure", setting_exposure) ||
246+
!jitsuyo::assign_val(config, "gain", setting_gain))
247+
{
248+
std::cout << "Error found at section `capture_settings`" << std::endl;
249+
throw std::runtime_error("Failed to load config file `" + path + "capture_settings.json`");
228250
}
229251

252+
capture_setting.brightness.set(setting_brightness);
253+
capture_setting.contrast.set(setting_contrast);
254+
capture_setting.saturation.set(setting_saturation);
255+
capture_setting.temperature.set(setting_temperature);
256+
capture_setting.exposure.set(setting_exposure);
257+
capture_setting.gain.set(setting_gain);
258+
230259
configure_capture_setting(capture_setting);
231260
}
232261

src/shisen_cpp/camera/provider/image_provider.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ ImageProvider::ImageProvider(const Options & options)
3838

3939
video_capture->set(cv::CAP_PROP_FRAME_WIDTH, options.width);
4040
video_capture->set(cv::CAP_PROP_FRAME_HEIGHT, options.height);
41+
video_capture->set(cv::CAP_PROP_AUTOFOCUS, 0); // Disable autofocus
42+
video_capture->set(cv::CAP_PROP_AUTO_WB, 0); // Disable auto white balance
43+
video_capture->set(cv::CAP_PROP_AUTO_EXPOSURE, 1); // Set auto exposure to manual mode
44+
video_capture->set(cv::CAP_PROP_SHARPNESS, 0); // Set sharpness to 0
45+
video_capture->set(cv::CAP_PROP_FOCUS, 0); // Set focus to 0
4146
}
4247

4348
ImageProvider::~ImageProvider()

src/shisen_cpp/config/grpc/call_data_get_capture_setting.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020

2121
#include <rclcpp/rclcpp.hpp>
2222
#include <shisen_cpp/config/grpc/call_data_get_capture_setting.hpp>
23-
#include <shisen_cpp/config/utils/config.hpp>
2423
#include <shisen_interfaces/shisen.grpc.pb.h>
2524
#include <shisen_interfaces/shisen.pb.h>
25+
#include <jitsuyo/config.hpp>
2626

2727
namespace shisen_cpp
2828
{
@@ -46,9 +46,14 @@ void CallDataGetCaptureSetting::WaitForRequest()
4646

4747
void CallDataGetCaptureSetting::HandleRequest()
4848
{
49-
Config config(path_);
49+
nlohmann::json data;
50+
if (!jitsuyo::load_config(path_, "capture_settings.json", data)) {
51+
RCLCPP_ERROR(rclcpp::get_logger("Get config"), "Failed to load config!");
52+
return;
53+
}
54+
std::string capture_setting = data.dump();
5055
try {
51-
reply_.set_json_capture(config.get_capture_setting("capture"));
56+
reply_.set_json_capture(capture_setting);
5257
RCLCPP_INFO(rclcpp::get_logger("Get config"), "config has been sent!");
5358
} catch (nlohmann::json::exception & e) {
5459
RCLCPP_ERROR(rclcpp::get_logger("Publish config"), e.what());

src/shisen_cpp/config/utils/config.cpp renamed to src/shisen_cpp/config/grpc/call_data_record_image.cpp

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,40 +18,37 @@
1818
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1919
// THE SOFTWARE.
2020

21-
#include <shisen_cpp/config/utils/config.hpp>
22-
23-
#include <fstream>
24-
#include <iomanip>
25-
#include <string>
21+
#include <rclcpp/rclcpp.hpp>
22+
#include <shisen_cpp/config/grpc/call_data_record_image.hpp>
23+
#include <shisen_interfaces/shisen.grpc.pb.h>
24+
#include <shisen_interfaces/shisen.pb.h>
2625

2726
namespace shisen_cpp
2827
{
29-
Config::Config(const std::string & path) : path(path) {}
30-
31-
std::string Config::get_capture_setting(const std::string & key) const
28+
CallDataRecordImage::CallDataRecordImage(
29+
shisen_interfaces::proto::Config::AsyncService * service, grpc::ServerCompletionQueue * cq,
30+
const std::string & path, const std::shared_ptr<camera::CameraNode>& camera_node)
31+
: CallData(service, cq, path), camera_node_(camera_node)
3232
{
33-
if (key == "capture") {
34-
std::ifstream capture_file(path + "capture_settings.json");
35-
nlohmann::json capture_data = nlohmann::json::parse(capture_file);
36-
return capture_data.dump();
37-
}
38-
39-
return "";
33+
Proceed();
4034
}
4135

42-
nlohmann::json Config::get_grpc_config() const
36+
void CallDataRecordImage::AddNextToCompletionQueue()
4337
{
44-
std::ifstream grpc_file(path + "grpc.json");
45-
nlohmann::json grpc_data = nlohmann::json::parse(grpc_file);
46-
grpc_file.close();
47-
return grpc_data;
38+
new CallDataRecordImage(service_, cq_, path_, camera_node_);
4839
}
4940

50-
void Config::save_capture_setting(const nlohmann::json & capture_data)
41+
void CallDataRecordImage::WaitForRequest()
5142
{
52-
std::ofstream capture_file(path + "capture_settings.json", std::ios::out | std::ios::trunc);
53-
capture_file << std::setw(2) << capture_data << std::endl;
54-
capture_file.close();
43+
service_->RequestRecordImage(&ctx_, &request_, &responder_, cq_, cq_, this);
5544
}
5645

46+
void CallDataRecordImage::HandleRequest()
47+
{
48+
try {
49+
camera_node_->save_image(camera_node_->get_mat());
50+
} catch(const std::exception& e) {
51+
RCLCPP_ERROR(rclcpp::get_logger("Record Image"), e.what());
52+
}
53+
}
5754
} // namespace shisen_cpp

0 commit comments

Comments
 (0)