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

Package for reading from dinolite usb microscope #234

Open
wants to merge 65 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
c7024df
webcam stream test with python
wang-edward Jan 28, 2023
e47b232
short gitignore
wang-edward Feb 4, 2023
aee3efe
add cmakelist
wang-edward Feb 4, 2023
5b34843
package init
wang-edward Feb 4, 2023
ba7fa3d
info file for camera setup
wang-edward Feb 4, 2023
250fc78
camera node publisher
wang-edward Feb 4, 2023
d7572de
camera context to simplify config
wang-edward Feb 4, 2023
6f1fb23
init launch file
wang-edward Feb 4, 2023
35f46a0
image_common to ci for camera_calibration_parsers
wang-edward Feb 4, 2023
f7b1c1d
add camera_calibration_parsers to package.xml
wang-edward Feb 4, 2023
29663b7
add science to ci
wang-edward Feb 5, 2023
6e24d39
add linters
wang-edward Feb 5, 2023
c32cdfa
add linterst to package.xml
wang-edward Feb 5, 2023
396f91f
get rid of camera calibration #yolo
wang-edward Feb 5, 2023
9ad82a1
implement proper fps
wang-edward Feb 5, 2023
d5fcac0
simplify fps
wang-edward Feb 5, 2023
7565f41
remove camera calibration
wang-edward Feb 5, 2023
61a1a5d
add launch file
wang-edward Feb 5, 2023
02752d1
update ci packages with dinolite
wang-edward Feb 5, 2023
90af7b0
webcam stream test with python
wang-edward Jan 28, 2023
7dfc0b0
short gitignore
wang-edward Feb 4, 2023
9caa789
add cmakelist
wang-edward Feb 4, 2023
5783dbc
package init
wang-edward Feb 4, 2023
24e31de
info file for camera setup
wang-edward Feb 4, 2023
0060fd2
camera node publisher
wang-edward Feb 4, 2023
1383270
camera context to simplify config
wang-edward Feb 4, 2023
382508a
init launch file
wang-edward Feb 4, 2023
7473cc0
image_common to ci for camera_calibration_parsers
wang-edward Feb 4, 2023
fc4af48
add camera_calibration_parsers to package.xml
wang-edward Feb 4, 2023
06b4a16
add science to ci
wang-edward Feb 5, 2023
2517951
add linters
wang-edward Feb 5, 2023
f8350fe
add linterst to package.xml
wang-edward Feb 5, 2023
e3f41f7
get rid of camera calibration #yolo
wang-edward Feb 5, 2023
d7a9d93
implement proper fps
wang-edward Feb 5, 2023
de1ec7e
simplify fps
wang-edward Feb 5, 2023
ef1a74d
remove camera calibration
wang-edward Feb 5, 2023
199b1f7
add launch file
wang-edward Feb 5, 2023
4dbe870
update ci packages with dinolite
wang-edward Feb 5, 2023
97b7f8c
remove camera calibration parsers from CMakeLists
wang-edward Feb 5, 2023
5c3b6f0
remove include camera calibration
wang-edward Feb 5, 2023
e7a7151
run ament_clang_format --reformat
wang-edward Feb 6, 2023
cd1aa6d
formatting
wang-edward Feb 6, 2023
fe39549
more formatting
wang-edward Feb 6, 2023
85f86aa
more formatting 2
wang-edward Feb 6, 2023
fb7e702
format launch
wang-edward Feb 8, 2023
056f8e1
more python formatting (should pass?)
wang-edward Feb 8, 2023
3e703ea
more py format
wang-edward Feb 8, 2023
37b3d1f
more py format 2
wang-edward Feb 8, 2023
5888c89
fill out package.xml
wang-edward Feb 8, 2023
34b2c2c
cleanup unused code
wang-edward Feb 8, 2023
4380685
move webcam_test.py to scripts folder
wang-edward Feb 9, 2023
f611ea0
add ros2 assert
wang-edward Feb 9, 2023
7e761d9
fix launch typo
wang-edward Feb 9, 2023
4e3e460
ros assert, fix topicname, cpp time, detail header
wang-edward Feb 9, 2023
6ea2b26
format
wang-edward Feb 9, 2023
8a18024
remove logging
wang-edward Feb 9, 2023
8124a72
use ros2 now()
wang-edward Feb 9, 2023
636a765
cleanup cmakelists
wang-edward Feb 11, 2023
0e70285
changed smart ptr to stack var
wang-edward Apr 3, 2023
4e0bef9
resolve conflicts
wang-edward May 18, 2023
77ef65b
more conflict
wang-edward May 18, 2023
1d7ebb4
add camera testing script (py)
wang-edward May 18, 2023
884097c
add webcam test script
wang-edward Apr 29, 2024
4d380c7
Merge branch 'user/wang-edward/217/science-dinolite' of https://githu…
wang-edward Apr 29, 2024
457d930
webcam test and config
wang-edward Apr 29, 2024
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 .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ env:
uwrt_mars_rover_drivetrain
uwrt_mars_rover_drivetrain_description
uwrt_mars_rover_drivetrain_hw
dinolite
ROS_DISTRO: galactic
IMAGE: "rostooling/setup-ros-docker:ubuntu-focal-ros-galactic-desktop-latest"

Expand Down
12 changes: 2 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,9 @@
5. Update your system before continuing: `sudo apt update -y --no-install-recommends && sudo apt dist-upgrade -y`
6. Install `rosdep`, the ROS dependency manager: `sudo apt install -y python3-rosdep`
7. Download the repository's upstream dependencies: `vcs import --input uwrt_mars_rover/common_upstream_dependencies.repos`
8. Update rosdep via `rosdep update --include-eol-distros`, including end-of-life ROS2 distros (we use Galactic).
9. Navigate back to the root of your workspace, and install all dependencies for your ROS packages: `rosdep install --from-paths src -y --ignore-src`.
8. Navigate back to the root of your workspace, and install all dependencies for your ROS packages: `RUN rosdep install --from-paths src -y --ignore-src`

You can re-navigate to the root of your workspace at any time and rerun #8 and #9 to update your ROS packages' dependencies.
For clarification, the repository should live in `~/ros2_ws/src/uwrt_mars_rover`.

### Building and Installing the Repository
1. Run `source /opt/ros/galactic/setup.bash`
2. Navigate to the root of your ROS2 workspace (e.g: `cd ~/ros2_ws`)
3. Build everything in the workspace: `colcon build`
4. Install the built files: `. install/setup.bash`
You can re-navigate to the root of your workspace at any time and rerun #8 to update your ROS packages' dependencies.


## Adding Dependencies
Expand Down
1 change: 1 addition & 0 deletions uwrt_mars_rover_science/dinolite/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
settings.json
112 changes: 112 additions & 0 deletions uwrt_mars_rover_science/dinolite/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
cmake_minimum_required(VERSION 3.8)
project(dinolite)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# Try for OpenCV 4.X, but settle for whatever is installed
find_package(OpenCV 4 QUIET)
if (NOT OpenCV_FOUND)
find_package(OpenCV REQUIRED)
endif ()
message(STATUS "Found OpenCV version ${OpenCV_VERSION}")

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(camera_calibration_parsers REQUIRED)
find_package(class_loader REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_components REQUIRED)
find_package(sensor_msgs REQUIRED)

include_directories(
include
)

# Create ament index resource which references the libraries in the binary dir
set(node_plugins "")

#=============
# OpenCV camera node
#=============

add_library(
cam_node SHARED
src/cam_node.cpp
)
target_compile_definitions(
cam_node
PRIVATE "COMPOSITION_BUILDING_DLL"
)
ament_target_dependencies(cam_node
camera_calibration_parsers
class_loader
OpenCV
rclcpp
rclcpp_components
sensor_msgs
)
rclcpp_components_register_nodes(cam_node "dinolite::CamNode")
set(node_plugins "${node_plugins}dinolite::CamNode;$<TARGET_FILE:cam_node>\n")

#=============
# Test subscriber node
#=============

# add_library(
# subscriber_node SHARED
# src/subscriber_node.cpp
# )
# target_compile_definitions(
# subscriber_node
# PRIVATE "COMPOSITION_BUILDING_DLL"
# )
# ament_target_dependencies( subscriber_node
# class_loader
# rclcpp
# rclcpp_components
# sensor_msgs
# )
# rclcpp_components_register_nodes(subscriber_node "dinolite::ImageSubscriberNode")
# set(node_plugins "${node_plugins}dinolite::ImageSubscriberNode;$<TARGET_FILE:subscriber_node>\n")

# Install nodes
install(
TARGETS cam_node
EXPORT export_cam_node
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
)

# install(
# TARGETS subscriber_node
# EXPORT export_subscriber_node
# ARCHIVE DESTINATION lib
# LIBRARY DESTINATION lib
# RUNTIME DESTINATION bin
# )

# Install various directories
install(
DIRECTORY launch
DESTINATION share/${PROJECT_NAME}
)
install(
DIRECTORY config
DESTINATION share/${PROJECT_NAME}
)


ament_export_dependencies(class_loader)

ament_export_include_directories(include)

ament_export_targets(export_cam_node)
# ament_export_targets(export_cam_node export_subscriber_node)

ament_export_libraries(gscam_node subscriber_node)
ament_package()


29 changes: 29 additions & 0 deletions uwrt_mars_rover_science/dinolite/config/info.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Dinolite microscope camera intrinsics

[image]

width
640

height
480

[dinolite]

camera matrix
0.00000 0.00000 0.00000
0.00000 0.00000 0.00000
0.00000 0.00000 0.00000

distortion
-0.41527 0.31874 -0.00197 0.00071 0.00000

rectification
1.00000 0.00000 0.00000
0.00000 1.00000 0.00000
0.00000 0.00000 1.00000

projection
0.00000 0.00000 0.00000 0.00000
0.00000 0.00000 0.00000 0.00000
0.00000 0.00000 0.00000 0.00000
41 changes: 41 additions & 0 deletions uwrt_mars_rover_science/dinolite/include/dinolite/cam_node.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include "dinolite/camera_context.hpp"

#include <string>
#include <rclcpp/rclcpp.hpp>

#include "opencv2/highgui/highgui.hpp"
#include "sensor_msgs/msg/camera_info.hpp"
#include "sensor_msgs/msg/image.hpp"

#include "camera_calibration_parsers/parse.hpp"

namespace dinolite {

class CamNode : public rclcpp::Node {

public:
explicit CamNode(const rclcpp::NodeOptions &options);

private:
void validate_parameters();
void frame();

void printer();

CameraContext cxt_;
std::shared_ptr<cv::VideoCapture> capture_;

sensor_msgs::msg::CameraInfo camera_info_msg_;

int publish_fps_;
rclcpp::Time next_stamp_;

rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr image_pub_;
rclcpp::Publisher<sensor_msgs::msg::CameraInfo>::SharedPtr camera_info_pub_;

rclcpp::TimerBase::SharedPtr timer_;
};

} // namespace dinolite
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once


#include <cmath>
#include <string>

namespace dinolite {

struct CameraContext {
const bool file_ = false;
const int fps_ = 30;
const std::string filename_ = "";
const int index_ = 0; // 0 is default index of webcam
const int width_ = 640;
const int height_ = 480;
const std::string camera_info_path_ = "install/dinolite/share/dinolite/config/info.ini";
const std::string camera_frame_id_ = "camera_frame";
};

}
1 change: 1 addition & 0 deletions uwrt_mars_rover_science/dinolite/launch/dinolite_launch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print("whats good")
25 changes: 25 additions & 0 deletions uwrt_mars_rover_science/dinolite/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>dinolite</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="[email protected]">edw</maintainer>
<license>TODO: License declaration</license>

<buildtool_depend>ament_cmake</buildtool_depend>

<depend>rclcpp</depend>
<depend>image_transport</depend>
<depend>cv_bridge</depend>
<depend>sensor_msgs</depend>
<depend>std_msgs</depend>
<depend>opencv2</depend>

<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>

<export>
<build_type>ament_cmake</build_type>
</export>
</package>
19 changes: 19 additions & 0 deletions uwrt_mars_rover_science/dinolite/scripts/webcam_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""Script for testing webcam connection to opencv."""

import cv2

# 0 is default index of webcam
vid = cv2.VideoCapture(0)

while(True):
# read frame
ret, frame = vid.read()
# display frame
cv2.imshow('frame', frame)

# press q to quit
if cv2.waitKey(1) & 0xFF == ord('q'):
break

vid.release()
cv2.destroyAllWindows()
Binary file not shown.
106 changes: 106 additions & 0 deletions uwrt_mars_rover_science/dinolite/src/cam_node.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include "dinolite/cam_node.hpp"

namespace dinolite {

std::string mat_type2encoding(int mat_type) {
switch (mat_type) {
case CV_8UC1:
return "mono8";
case CV_8UC3:
return "bgr8";
case CV_16SC1:
return "mono16";
case CV_8UC4:
return "rgba8";
default:
throw std::runtime_error("unsupported encoding type");
}
}

CamNode:: CamNode(const rclcpp::NodeOptions &options) : Node("dinolite_cam", options) {
RCLCPP_INFO(get_logger(), "hello wordln");
RCLCPP_INFO(get_logger(), "OpenCV version: %d", CV_VERSION_MAJOR);

capture_ = std::make_shared<cv::VideoCapture>(cxt_.index_);

if (!capture_->isOpened()) {
RCLCPP_ERROR(get_logger(), "cannot open device %d", cxt_.index_);
return;
}
if (cxt_.height_ > 0) {
capture_->set(cv::CAP_PROP_FRAME_HEIGHT, cxt_.height_);
}
if (cxt_.width_ > 0) {
capture_->set(cv::CAP_PROP_FRAME_WIDTH, cxt_.width_);
}
if (cxt_.fps_ > 0) {
capture_->set(cv::CAP_PROP_FPS, cxt_.fps_);
}

double width = capture_->get(cv::CAP_PROP_FRAME_WIDTH);
double height = capture_->get(cv::CAP_PROP_FRAME_HEIGHT);
double fps = capture_->get(cv::CAP_PROP_FPS);

RCLCPP_INFO(get_logger(),
"device %d open, width %g, height %g, device fps %g",
cxt_.index_, width, height, fps
);

assert(!cxt_.camera_info_path_.empty()); // readCalibration will crash if file_name is ""

std::string camera_name;
if (camera_calibration_parsers::readCalibration(cxt_.camera_info_path_, camera_name, camera_info_msg_)) {
RCLCPP_INFO(get_logger(), "got camera info for '%s'", camera_name.c_str());
camera_info_msg_.header.frame_id = cxt_.camera_frame_id_;
camera_info_pub_ = create_publisher<sensor_msgs::msg::CameraInfo>("camera_info", 10);
} else {
RCLCPP_ERROR(get_logger(), "cannot get camera info, will not publish");
camera_info_pub_ = nullptr;
}

image_pub_ = create_publisher<sensor_msgs::msg::Image>("image_raw", 10);

// send message
timer_ = create_wall_timer(
std::chrono::duration
<int, std::chrono::milliseconds::period>(1),
std::bind(&CamNode::frame, this)
);

}

void CamNode:: frame() {
cv::Mat frame;
while(rclcpp::ok()) {
if (!capture_->read(frame)) {
RCLCPP_INFO(get_logger(), "EOF, stop publishing");
break;
}

auto stamp = now();

sensor_msgs::msg::Image::UniquePtr image_msg(new sensor_msgs::msg::Image());

image_msg->header.stamp = stamp;
image_msg->header.frame_id = cxt_.camera_frame_id_;
image_msg->height = frame.rows;
image_msg->width = frame.cols;
image_msg->encoding = mat_type2encoding(frame.type());
image_msg->is_bigendian = false;
image_msg->step = static_cast<sensor_msgs::msg::Image::_step_type>(frame.step);
image_msg->data.assign(frame.datastart, frame.dataend);

// publish message
image_pub_->publish(std::move(image_msg));
if (camera_info_pub_) {
camera_info_msg_.header.stamp = stamp;
camera_info_pub_->publish(camera_info_msg_);
}
}
}

} // namespace dinolite

#include "rclcpp_components/register_node_macro.hpp"

RCLCPP_COMPONENTS_REGISTER_NODE(dinolite::CamNode)
Loading
Loading