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

Adamc/sub camera temp #82

Closed
wants to merge 52 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
2c34894
Set up 2 basic nodes
VladimirKupryukhin Sep 28, 2023
885505c
Added cv_bridge
VladimirKupryukhin Sep 28, 2023
888c965
Publishing works I think
VladimirKupryukhin Sep 29, 2023
ce1e086
Added video test
Oct 10, 2023
c7f7e47
launch_only_docker connects to gui. Video output confirmed good
Oct 10, 2023
5e7ef6f
Changed to compressed image
Mar 2, 2024
22c00a8
Changed to compressed image
Mar 2, 2024
b421c7c
stopped running camera test and slower streaming for testing
TrickFireRobotic Apr 11, 2024
1f3c975
Spin up a camera node for every camera detected
Apr 15, 2024
418ae4e
Pushing any changes that were done. I am switching branches -vlad
TrickFireRobotic Apr 17, 2024
043ae57
multi threaded executor for all cameras
Apr 22, 2024
3261f6a
changed to individual topic for each camera
Apr 22, 2024
9ea485d
bug fix to append string to string
Apr 22, 2024
a6d8cd4
another bug fix to iterate camera topic name
Apr 22, 2024
81fa80b
added a test for custom camera executor
Apr 29, 2024
c8a0373
temporarily removing camera node because it's broken
Apr 29, 2024
c2d3b16
added camera node back
Apr 29, 2024
ec359ae
changed executor publisher name because name conflict with roscamera
Apr 29, 2024
c694f91
something is wrong with publisher name. removed executor test from la…
Apr 29, 2024
046154e
Implemented camera toggle control via a mission control topic called …
dkim03 Sep 9, 2024
46eb010
delete camera_subscriber (unused)
dkim03 Sep 28, 2024
0153dc0
rebase + updated roscamera.py with on, off functionality instead of t…
dkim03 Sep 28, 2024
d99ca85
update settings.json
dkim03 Oct 22, 2024
7483ccf
Robot Interface Merge (#24)
Chillingfire Dec 1, 2023
352d458
Merge RobotInfo (#29)
loukylor Jan 5, 2024
e4d1e52
Merge drivebase code (#30)
K1aymore Mar 26, 2024
921afb8
Rewrite can_moteus (#41)
VladimirKupryukhin Jul 11, 2024
805ea8c
Send Telemetry Data to Mission Control (#53)
VladimirKupryukhin Aug 23, 2024
88a66fe
arm: Implement basic arm functionality (velocity-based) with an xbox …
VladimirKupryukhin Sep 10, 2024
c57e7ad
Remove unused packages, remove unused docs, remove unused shell files
VladimirKupryukhin Sep 10, 2024
f1e339f
[reformat] remove existing linter tests
loukylor Sep 10, 2024
67a5b2a
THE GREAT REFORMATTENING
loukylor Sep 11, 2024
4798ee9
THE GREAT REFORMATTENING (pt 2)
loukylor Sep 11, 2024
09ce882
[lib] Refactor non-node modules to be easier to work with (#59)
loukylor Sep 16, 2024
898940b
[lib] Add support for setting moteus config values in lib #61 (#62)
VladimirKupryukhin Sep 16, 2024
d38efe6
[launch] Make a shell script to launch, run, build, create docker ima…
VladimirKupryukhin Sep 18, 2024
3a5fb14
[launch] added -t for tty
VladimirKupryukhin Sep 18, 2024
71b11ad
[launch] Added some comments to container_launch.sh
VladimirKupryukhin Sep 18, 2024
e8ede72
Automatically stop the old container from running
VladimirKupryukhin Sep 18, 2024
67610f4
Adds an Example Node as well as Some Additional Documentation (#63)
VladimirKupryukhin Sep 19, 2024
75d032e
[doc/example] remove example node from viator lauch (#65)
loukylor Sep 19, 2024
0b5094f
Hong/heartbeat (#70)
dkim03 Oct 22, 2024
8548751
added the missing Docker modules in the Dockerfile for OpenCV and cv…
dkim03 Oct 25, 2024
e938fc9
Merge branch 'main' into adamc/sub-camera-temp
adamseth2 Nov 13, 2024
6c78982
Final Luncheon code
TrickFireRobotic Nov 25, 2024
b5df7d6
Merge branch 'main' into adamc/sub-camera-temp
uellenberg Jan 11, 2025
9cf64e8
Cleanup
uellenberg Jan 11, 2025
451bc55
Further cleanup
uellenberg Jan 17, 2025
946b279
Update workflow to work with submodules
uellenberg Jan 17, 2025
f4fe9fe
Fix workflow erroring on vision_opencv
uellenberg Jan 17, 2025
849fb87
Fix pylint
uellenberg Jan 17, 2025
5b1b786
Remove old camera on/off functionality
uellenberg Jan 17, 2025
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
10 changes: 9 additions & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Base image: Ubuntu 20.04 with ROS2 Humble installed
FROM ros:humble

# Install dependencies from apt
RUN apt-get update && apt-get install -y \
# To use git in the container
Expand All @@ -15,6 +14,12 @@ RUN apt-get update && apt-get install -y \
can-utils \
iproute2 \
kmod \
# Used for cv_bridge
python3-numpy \
libboost-python-dev \
# OpenCV
libopencv-dev \
python3-opencv \
# Clean out the apt lists after `apt-get update`
&& rm -rf /var/lib/apt/lists/*

Expand All @@ -24,6 +29,9 @@ RUN pip3 install moteus

RUN pip3 install pyusb

# Install OpenCV for python
RUN pip3 install opencv-python

# Update pydocstyle to remove a deprecation warning when testing for PEP257
RUN pip install --upgrade pydocstyle

Expand Down
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"workspaceFolder": "/home/trickfire/${localWorkspaceFolderBasename}",
"runArgs": [
"--cap-add=SYS_PTRACE",
//"--device=/dev/ttyUSB0",
"--device=/dev/video0",
"--security-opt", "seccomp=unconfined"
],
"customizations": {
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
# Black has a first-party ci/cd solution doesn't require python or setup, so use that
# before running setup.
- name: Run Black
uses: psf/black@stable
with:
options: "--check --verbose"
options: "--check --verbose --exclude vision_opencv"
src: "./src"
version: 24.8.0
- name: Setup Python
Expand All @@ -26,7 +28,7 @@ jobs:
- name: Run Pylint
# Ignoring ros packages is unideal, but installing them as packages is not trivial
run: |
pylint --fail-under=8 --ignored-modules=rclpy,std_msgs,ament_copyright,ament_flake8,pytest,launch ./src
pylint --fail-under=8 --ignored-modules=rclpy,std_msgs,ament_copyright,ament_flake8,pytest,launch,vision_opencv --ignore-paths=^src/vision_opencv.*$ ./src
- name: Run Mypy
run: |
mypy --exclude /test/ --exclude setup\.py ./src
mypy --exclude /test/ --exclude setup\.py --exclude vision_opencv ./src
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "src/vision_opencv"]
path = src/vision_opencv
url = https://github.com/ros-perception/vision_opencv.git
branch = ros2
Empty file added src/camera/camera/__init__.py
Empty file.
111 changes: 111 additions & 0 deletions src/camera/camera/roscamera.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import cv2 # OpenCV library
import rclpy # Python Client Library for ROS 2
from cv_bridge import CvBridge # Package to convert between ROS and OpenCV Images
from rclpy.executors import MultiThreadedExecutor
from rclpy.node import Node # Handles the creation of nodes
from sensor_msgs.msg import CompressedImage # Image is the message type


def getCameras() -> list[int]:
"""
Function returns a list of working camera IDs to capture every camera connected to the robot
"""

non_working_ports = 0
dev_port = 0
working_ports = []

while non_working_ports < 6:
camera = cv2.VideoCapture(dev_port)
if not camera.isOpened():
non_working_ports += 1
else:
is_reading, img = camera.read()
_ = camera.get(3)
_ = camera.get(4)
if is_reading:
working_ports.append(dev_port)

dev_port += 1

return working_ports


class RosCamera(Node):

def __init__(self, topicName: str, camera: int):
super().__init__("ros_camera")
self.get_logger().info("Launching ros_camera node")

# Create the publisher. This publisher will publish an Image
# to the video_frames topic. The queue size is 10 messages.
self._publisher = self.create_publisher(CompressedImage, topicName, 10)
self.get_logger().info("Created Publisher " + topicName)

# We will publish a message every 0.1 seconds
# timer_period = 0.1 # seconds
timer_period = 0.1 # seconds

# Create the timer
self.timer = self.create_timer(timer_period, self.publishCameraFrame)

# Create a VideoCapture object
# The argument '0' gets the default webcam.
self.cap = cv2.VideoCapture(camera)
self.get_logger().info(
"Using video ID: " + str(camera) + ", ON: " + str(self.cap.isOpened())
)

# Used to convert between ROS and OpenCV images
self.br = CvBridge()

# Declare parameters for each 'ros_camera' node thread
self.declare_parameter("cameraNumber", camera)

def publishCameraFrame(self) -> None:
"""
Callback function publishes a frame captured from a camera to /video_framesX (X is specific
camera ID) every 0.1 seconds
"""

# Capture frame-by-frame
# This method returns True/False as well as the video frame.
ret, frame = self.cap.read()

if ret:
# Publish the image.
self._publisher.publish(self.br.cv2_to_compressed_imgmsg(frame))


def main(args: list[str] | None = None) -> None:
"""
The entry point of the node.
"""

rclpy.init(args=args)
try:
# We need an executor because running .spin() is a blocking function.
# using the MultiThreadedExecutor, we can control multiple nodes
executor = MultiThreadedExecutor()
nodes = []
camera_num = 0

for camera_id in getCameras():
node = RosCamera("video_frames" + str(camera_num), camera_id)
nodes.append(node)
executor.add_node(node)
camera_num += 1

try:
executor.spin()
finally:
executor.shutdown()
for node in nodes:
node.destroy_node()

finally:
rclpy.shutdown()


if __name__ == "__main__":
main()
18 changes: 18 additions & 0 deletions src/camera/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?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>camera</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="kimdavid2222@gmail.com">trickfire</maintainer>
<license>TODO: License declaration</license>

<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>python3-pytest</test_depend>

<export>
<build_type>ament_python</build_type>
</export>
</package>
Empty file added src/camera/resource/camera
Empty file.
4 changes: 4 additions & 0 deletions src/camera/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[develop]
script_dir=$base/lib/camera
[install]
install_scripts=$base/lib/camera
23 changes: 23 additions & 0 deletions src/camera/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from setuptools import find_packages, setup

package_name = "camera"

setup(
name=package_name,
version="0.0.0",
packages=find_packages(exclude=["test"]),
data_files=[
("share/ament_index/resource_index/packages", ["resource/" + package_name]),
("share/" + package_name, ["package.xml"]),
],
install_requires=["setuptools"],
zip_safe=True,
maintainer="trickfire",
maintainer_email="kimdavid2222@gmail.com",
description="TODO: Package description",
license="TODO: License declaration",
tests_require=["pytest"],
entry_points={
"console_scripts": ["roscamera = camera.roscamera:main"],
},
)
25 changes: 25 additions & 0 deletions src/camera/test/test_copyright.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright 2015 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pytest
from ament_copyright.main import main


# Remove the `skip` decorator once the source file(s) have a copyright header
@pytest.mark.skip(reason="No copyright header has been placed in the generated source file.")
@pytest.mark.copyright
@pytest.mark.linter
def test_copyright():
rc = main(argv=[".", "test"])
assert rc == 0, "Found errors"
3 changes: 3 additions & 0 deletions src/viator_launch/launch/robot.launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

heartbeat_node = Node(package="heartbeat", executable="heartbeat", name="heartbeat_node")

camera_node = Node(package="camera", executable="roscamera", name="camera_node")

# This is the example node. It will show ROS timers, subscribers, and publishers
# To include it in the startup, add it to the array in the generate_launch_description() method
example_node = Node(package="example_node", executable="myExampleNode", name="my_example_node")
Expand All @@ -44,6 +46,7 @@ def generate_launch_description() -> launch.LaunchDescription: # pylint: disabl
mission_control_updater_node,
arm_node,
heartbeat_node,
camera_node,
launch_include,
]
)
1 change: 1 addition & 0 deletions src/viator_launch/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<exec_depend>ros2launch</exec_depend>
<exec_depend>mission_control_updater</exec_depend>
<exec_depend>arm</exec_depend>
<exec_depend>camera</exec_depend>
<exec_depend>example_node</exec_depend>


Expand Down
1 change: 1 addition & 0 deletions src/vision_opencv
Submodule vision_opencv added at a34a0c
Loading