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

Camera get ip #10

Draft
wants to merge 23 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b21a66c
new subscriber for surface ip-address
anawandh Jan 18, 2025
74ca83d
New github actions testing file
anawandh Jan 23, 2025
479e011
updated github action testing to check for active nodes
KiraYang3 Jan 23, 2025
687136d
changed ros-tooling version in CI tests
anawandh Jan 23, 2025
667fe30
Changed ubuntu version on CI test
anawandh Jan 23, 2025
8353458
removed the requirements.txt dependency from CI test
KiraYang3 Jan 23, 2025
3cb0bfb
commented out node launch files that produce errors, added ros source…
KiraYang3 Jan 23, 2025
f708dd6
Added topic name and timer to get_ip subscriber
anawandh Feb 1, 2025
8df47f0
Re-format sensor files
adamkahl Feb 2, 2025
0664045
updated launch_camera to search for device names
KiraYang3 Feb 6, 2025
2a685ab
Enhance launch_camera to identify and log third exploreHD device
adamkahl Feb 6, 2025
19dd5c1
Add changes from core
adamkahl Feb 6, 2025
3f01622
updated camera commands with ffmpeg command
KiraYang3 Feb 6, 2025
678b794
Camera auto launch sequence complete
adamkahl Feb 6, 2025
2b38e10
Don't gitignore utils folder
adamkahl Feb 6, 2025
b5a7f51
Add a readme for the cameras
adamkahl Feb 6, 2025
9c64e94
Isolate logic for finding camera devices and add heartbeat
adamkahl Feb 6, 2025
d2c36db
Refactor camera device variable naming for clarity
adamkahl Feb 6, 2025
780e74c
Add VSCode settings for Python analysis and autocomplete paths
adamkahl Feb 6, 2025
70ed67f
Added some documentation explaining how these nodes work
adamkahl Feb 6, 2025
783d2b9
Clean up code and add some comments
adamkahl Feb 6, 2025
14d70b4
Pull launch file from master
adamkahl Feb 6, 2025
5630f88
Fix CI not completing
adamkahl Feb 6, 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
48 changes: 48 additions & 0 deletions .github/workflows/build_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: X17-Core Build Test
on:
push:
branches:
- camera_get_ip
pull_request:
branches:
- camera_get_ip
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-22.04 # Use Ubuntu 22.04 (Jammy) for ROS 2 Humble
steps:
# Check out the repository
- name: Checkout code
uses: actions/checkout@v4

# Set up ROS 2 (Humble)
- name: Set up ROS 2
uses: ros-tooling/setup-ros@v0.7
with:
required-ros-distributions: humble

# Install dependencies from requirements.txt
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y python3-pip

# Execute the build script
- name: Build
run: |
chmod +x scripts/build.sh
scripts/build.sh

# Execute the run script
- name: Start and check ROS 2 nodes
run: |
chmod +x scripts/run.sh
scripts/run.sh &
sleep 15 # Give nodes time to start
# Kill ROS 2 nodes
echo "Killing ROS 2 nodes:"
pkill -f ros2 || true # Success message

- name: Success
run: echo "Success!"
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.idea
build
install
utils
log
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"python.analysis.extraPaths": ["utils"],
"python.autoComplete.extraPaths": ["utils"]
}
6 changes: 3 additions & 3 deletions rov_launch/launch/core_launch.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
launch:
- include:
file: $(find-pkg-share thrust_control)/launch/thrust_control_launch.yaml
file: $(find-pkg-share sensors)/launch/sensors_launch.yaml
file: $(find-pkg-share tools)/launch/tools_launch.yaml
file: $(find-pkg-share videos)/launch/videos_launch.yaml
# file: $(find-pkg-share sensors)/launch/sensors_launch.yaml
# file: $(find-pkg-share tools)/launch/tools_launch.yaml
# file: $(find-pkg-share videos)/launch/videos_launch.yaml
Empty file modified scripts/build.sh
100644 → 100755
Empty file.
Empty file modified scripts/run.sh
100644 → 100755
Empty file.
5 changes: 4 additions & 1 deletion sensors/src/depth_sense.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#! /usr/bin/python3

import rclpy
from rclpy.node import Node

from std_msgs.msg import Float64

# Library for the depth sensor
# More info: https://github.com/bluerobotics/ms5837-python
import ms5837


Expand Down
1 change: 0 additions & 1 deletion sensors/src/imu_angle_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import rclpy
from rclpy.node import Node

from shared_msgs.msg import ImuMsg, ImuVelocityCommand


Expand Down
35 changes: 35 additions & 0 deletions utils/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 3.8)
project(utils)

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

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(ament_cmake_python REQUIRED)
find_package(rclpy REQUIRED)

ament_python_install_package(${PROJECT_NAME})

install(PROGRAMS
utils/heartbeat_helper.py
DESTINATION lib/${PROJECT_NAME}
)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)

if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()

ament_package()
27 changes: 27 additions & 0 deletions utils/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?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>utils</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="akahl@purdue.edu">adam</maintainer>
<license>TODO: License declaration</license>

<buildtool_depend>ament_cmake</buildtool_depend>
<buildtool_depend>ament_cmake_python</buildtool_depend>
<buildtool_depend>rosidl_default_generators</buildtool_depend>

<depend>rclpy</depend>

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

<exec_depend>builtin_interfaces</exec_depend>
<exec_depend>rosidl_default_generators</exec_depend>

<member_of_group>rosidl_interface_packages</member_of_group>

<export>
<build_type>ament_cmake</build_type>
</export>
</package>
File renamed without changes.
Empty file added utils/utils/__init__.py
Empty file.
31 changes: 31 additions & 0 deletions utils/utils/heartbeat_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#! /usr/bin/python3

from rclpy.node import Node
from std_msgs.msg import Header

class HeartbeatHelper:
def __init__(self, node: Node, topic_name="heartbeat", timer_period=5.0):
"""This class is used to publish a heartbeat message on a given topic at a given interval"""
self.timer_period = timer_period
self.node = node
self.publisher = self.node.create_publisher(Header, topic_name, 10)
self.timer = self.node.create_timer(timer_period, self.publish_heartbeat)

def publish_heartbeat(self):
"""Publish a heartbeat message on the topic"""
self.node.get_logger().info("Publishing heartbeat from {}".format(self.node.get_name()))
msg = Header()
msg.stamp = self.node.get_clock().now().to_msg()
msg.frame_id = self.node.get_name()
self.publisher.publish(msg)

def stop_heartbeat(self):
"""Stop the heartbeat timer"""
self.timer.cancel()
self.node.destroy_publisher(self.publisher)
self.node.get_logger().info(f'Heartbeat stopped for {self.node.get_name()}')

def start_heartbeat(self):
"""Start the heartbeat timer"""
self.timer = self.node.create_timer(self.timer_period, self.publish_heartbeat)
self.node.get_logger().info(f'Heartbeat started for {self.node.get_name()}')
File renamed without changes.
1 change: 1 addition & 0 deletions videos/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ ament_python_install_package(${PROJECT_NAME})

install(PROGRAMS
src/videos_launch.py
src/get_ip.py
DESTINATION lib/${PROJECT_NAME}
)

Expand Down
50 changes: 50 additions & 0 deletions videos/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Camera Streams

Our camera streams are designed to be as simple as possible to get up and running.

### How it works

There are two main nodes for this package:

1. `IpSubscriber` - This node is responsible for subscribing to the IP address of the the surface station, and when a valid IP address is received, it will start the camera nodes with the provided IP address.
2. `Camera` - This nodes is responsible for creating a ffmpeg stream from the camera, and publishing it to the surface station.

### IpSubscriber

This node first creates a subscription to the `surface_ip` topic and waits for a message to be published. When a message is published, it will start the camera nodes with the provided IP address.

After receiving the IP address, the node will run the command: `v4l2-ctl --list-devices`. This will list all the camera devices and their respective paths. The output will usually look something like this, with an entry for each connected video device:

```bash
exploreHD USB Camera: exploreHD (usb-0000:01:00.0-1.1.4):
/dev/video4
/dev/video5
/dev/video6
/dev/video7
/dev/media4
```

The various devices listed under the camera name are the different video devices that can be used to stream from the camera. They each correspond to a different format or resolution that the camera can stream in. The node currently selects the 3rd device listed for each camera, but this can be changed by modifying the `camera_device_number` parameter in the `get_ip.py` file.

The node will select the specified number of cameras. If there are more cameras than specified, the node will select the first specified number of cameras. If there are fewer cameras than specified, the node will select the available cameras.


The camera nodes will be launched with the following command:

```bash
ros2 run videos videos_launch.py --ros-args -p ip:={ip} -p device:={camera} -p camera_number:={i} -r __node:=camera{i}
```

Where `{ip}` is the IP address of the surface station, `{camera}` is the path to the camera device in the URL, and `{i}` is the camera number.

### Camera

This node is responsible for creating a ffmpeg stream from the camera, and publishing it to the surface station. The ffmpeg command is as follows:

```bash
ffmpeg -f v4l2 -fflags nobuffer -i dev_name -vcodec copy -g 10 -f rtsp rtsp_url
```

Where `dev_name` is the path to the camera device, and `rtsp_url` is the URL to publish the stream to.

To learn more about ffmpeg and its options, visit the [ffmpeg documentation](https://ffmpeg.org/ffmpeg.html).
36 changes: 2 additions & 34 deletions videos/launch/videos_launch.yaml
Original file line number Diff line number Diff line change
@@ -1,37 +1,5 @@
launch:
- node:
pkg: "videos"
exec: "videos_launch.py"
namespace: "rov"
name: "front_cam"
param:
- name: "dev_name"
type: "str"
value: "device=/dev/video2"
- name: "port_num"
type: "str"
value: "5600"
- node:
pkg: "videos"
exec: "videos_launch.py"
namespace: "rov"
name: "down_cam"
param:
- name: "dev_name"
type: "str"
value: "device=/dev/video6"
- name: "port_num"
type: "str"
value: "5601"
- node:
pkg: "videos"
exec: "videos_launch.py"
namespace: "rov"
name: "aft_cam"
param:
- name: "dev_name"
type: "str"
value: "device=/dev/video17"
- name: "port_num"
type: "str"
value: "5602"
exec: "get_ip.py"
namespace: "rov"
Loading