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

Migrate to ROS2 #373

Draft
wants to merge 26 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
83a8515
Move ROS2 proof-of-concept to parent (#367)
ShaanGondalia Oct 27, 2022
0d15575
Migrate camera_view package to ROS2
ShaanGondalia Oct 29, 2022
499c66f
Migrate simulation package to ROS2
ShaanGondalia Nov 5, 2022
9a79569
Improve log formatting
ShaanGondalia Nov 5, 2022
81e1ff0
Revert debug values
ShaanGondalia Nov 5, 2022
6002137
Update transform listener to tf2
ShaanGondalia Nov 5, 2022
19f1a1f
Update READMEs
ShaanGondalia Nov 5, 2022
73657ca
Revert some utilities
ShaanGondalia Nov 5, 2022
2079b4a
Update build script to colcon
ShaanGondalia Nov 5, 2022
0ecd75b
Migrate acoustics package to ROS2
ShaanGondalia Nov 7, 2022
0397dab
Migrate avt_camera package to ROS2
ShaanGondalia Nov 7, 2022
87bfefc
Clean up typos
ShaanGondalia Nov 7, 2022
3c0cbf9
Migrate data_pub package to ROS2
ShaanGondalia Nov 7, 2022
e9d7d02
Migrate robosub_description package to ROS2
ShaanGondalia Nov 7, 2022
94e8f9c
Migrate sensor_fusion package to ROS2
ShaanGondalia Nov 7, 2022
fca91d4
Migrate static_transforms package to ROS2
ShaanGondalia Nov 7, 2022
0b41345
Migrate system_utils package to ROS2
ShaanGondalia Nov 8, 2022
9b8809f
Fix remote termination for launch files
ShaanGondalia Nov 8, 2022
044ecf5
Update CI for temp builds
ShaanGondalia Nov 8, 2022
ae076fe
Add source to build workflow
ShaanGondalia Nov 8, 2022
39f7877
Fix source location in build workflow
ShaanGondalia Nov 8, 2022
0d2feef
Update CI to fail when launch files crash
ShaanGondalia Nov 9, 2022
fa839bf
Migrate cv package to ROS2
ShaanGondalia Nov 9, 2022
d9186fb
Add documentation on anonymous nodes in ROS2
ShaanGondalia Nov 9, 2022
622d826
Merge branch 'master' of github.com:DukeRobotics/robosub-ros into ros…
ShaanGondalia Nov 11, 2022
6dfb513
Migrate controls package to ROS2
ShaanGondalia Nov 13, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .github/workflows/build-artifacts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
needs: check-comment
strategy:
matrix:
arch: [arm64, amd64]
arch: [amd64]
fail-fast: false
env:
IMAGE_NAME: 'dukerobotics/robosub-ros:core-${{ matrix.arch }}'
Expand Down Expand Up @@ -63,7 +63,7 @@ jobs:
needs: [check-comment, core-docker]
strategy:
matrix:
arch: [arm64, amd64]
arch: [amd64]
fail-fast: false
env:
IMAGE_NAME: 'dukerobotics/robosub-ros:onboard-${{ matrix.arch }}'
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,15 @@ jobs:
- name: Start containers
run: |
docker tag ${IMAGE_NAME} dukerobotics/robosub-ros:onboard
docker-compose up -d
docker compose up -d
- name: Test build
run: docker exec ${SERVICE_NAME} ./build.sh
- name: Test Arduino build
if: matrix.arch == 'amd64'
run: docker exec ${SERVICE_NAME} ./.github/workflows/test_arduino.sh
- name: Test ROS launchfiles
if: matrix.arch == 'amd64'
run: docker exec -t ${SERVICE_NAME} bash -lc "python ./scripts/test-launch.py"
run: docker exec -t ${SERVICE_NAME} bash -lc "source onboard/ros2_ws/install/setup.bash && python ./scripts/test-launch.py"
- name: Push image to dockerhub
if: github.event_name == 'push'
run: |
Expand Down Expand Up @@ -150,11 +150,11 @@ jobs:
cd docker/${SERVICE_NAME}
docker build --build-arg BASE_IMAGE=${BASE_IMAGE} -t ${IMAGE_NAME} .
- name: Start containers
run: docker-compose up -d
run: docker compose up -d
- name: Test build
run: docker exec ${SERVICE_NAME} ./build.sh
- name: Test ROS launchfiles
run: docker exec -t ${SERVICE_NAME} bash -lc "python ./scripts/test-launch.py"
run: docker exec -t ${SERVICE_NAME} bash -lc "source landside/ros2_ws/install/setup.bash && python ./scripts/test-launch.py"
- name: Push image to dockerhub
if: github.event_name == 'push'
run: |
Expand All @@ -180,5 +180,5 @@ jobs:
- name: Test ROS launchfiles
shell: bash -elo pipefail {0}
run: |
source ${{ matrix.workspace }}/catkin_ws/devel/setup.bash
source ${{ matrix.workspace }}/ros2_ws/install/setup.bash
./scripts/test-launch.py
4 changes: 2 additions & 2 deletions .github/workflows/test_arduino.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
set -e

# shellcheck disable=SC1091
source onboard/catkin_ws/devel/setup.bash
rosrun offboard_comms arduino_upload.sh -c
source onboard/ros2_ws/install/setup.bash
# rosrun offboard_comms arduino_upload.sh -c
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
*/catkin_ws/devel
*/catkin_ws/logs

# ROS2/Ament
*/ros2_ws/build
*/ros2_ws/log
*/ros2_ws/install

# ROS_Serial
ros_lib/
ros_lib.zip
Expand All @@ -22,6 +27,8 @@ ros_lib.zip
# Video and Bags
*.avi
*.bag
**/bag
*.db3

# PyCharm/IntelliJ
.idea
Expand Down
195 changes: 195 additions & 0 deletions NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# Notes
To source ROS: `source /opt/ros/humble/setup.bash`

ROS2 removed the functionality of anonymous nodes. To get around this, all nodes that can have multiple instances should be ran with:

```bash
ros2 run <package> <node> --ros-args --remap __node:=<unique_name> -p <param_name>:=<param_val>
```

All launch files that create multiple nodes of the same type should assign them unique names accordingly.

## Bulding
For building, use `colcon build --symlink-install`, because colcon has no devel space. This allows us to change scripts without rebuilding for each change.

Post colcon build, run

```bash
source landside/ros2_ws/install/setup.bash
source onboard/ros2_ws/install/setup.bash
```

No `colcon clean`, instead `rm -r build install log`

## Writing nodes
Nodes now inherit from `rclpy.node.Node`, and are created via `super().__init__(self.NODE_NAME)`

`main()` should now include `rclpy.init()`

`rospy.spin()` should be moved from inside of node to `main()`

```python
try:
rclpy.init(args=args)
parser = JoystickParser()
rclpy.spin(parser)
except KeyboardInterrupt:
pass
except ExternalShutdownException:
raise
finally:
parser.destroy_node()
if rclpy.ok():
rclpy.shutdown()
```

Subscribers need QoS (Quality of Service) profiles. This is the 4th positional argument, use 10 for a default value.

`self.create_subscription(SimObjectArray, "/sim/object_points", self.callback, 10)`

### Time
Replace `rospy.Time.now()` with `self.get_clock().now()`

Replace `while not rospy.is_shutdown():` with `while rclpy.ok():`

Have to convert time to messages explicitly: `.to_msg().sec`

### Run Loops
Previously, run loops were written as:

```python
def run(self):
rate = rospy.Rate(self.RUN_LOOP_RATE)
while not rospy.is_shutdown():
# Do stuff
rate.sleep()
```

In ROS2, a way to do this is to create timers:

```python
class TestNode(Node)
def __init__(self):
super().__init__(self.NODE_NAME)
self.timer = self.create_timer(1/self.RUN_LOOP_RATE, self.run)

def run(self):
# Do stuff


def main():
tn = TestNode()
rclpy.spin(tn)
```

This allows us to take advantage of threading and have multiple "loops" running in a node cleanly. There are other methods, but this is generally the cleanest.

## Transforms
Replace `tf` with `tf_transformations`

Replace `import tf2` with `import tf2_ros`

To declare a transform listener in a node and transform a PoseStamped:
```python
import rclpy
from tf2_ros.transform_listener import TransformListener
from tf2_ros.buffer import Buffer
from tf2_geometry_msgs import do_transform_pose_stamped


class TestNode(rcply.node.Node):
super().__init__("node_name")
self.tf_buffer = Buffer()
self.tf_listener = TransformListener(self.tf_buffer, self)

pose_stamped = PoseStamped()
pose_stamped.header.frame_id = "source_frame"
transform = self.tf_buffer.lookup_transform("target_frame",
poses.header.frame_id,
rclpy.time.Time())
transformed_pose_stamped = do_transform_pose_stamped(poses, transform)
```


## ROSbags

Rosbags are no longer stored as .bag files. They are now stored as sqlite3 databases.

## Dependencies

### Core
```bash
pip install transforms3d
pip install setuptools==58.2.0
apt-get install ros-humble-resource-retriever
apt-get install ros-humble-cv-bridge
apt-get install ros-humble-tf2
apt-get install ros-humble-tf-transformations
apt-get install ros-humble-tf2-geometry-msgs
```

### Landside
```bash
apt-get install ros-humble-joy
apt-get install ros-humble-image-view
apt-get install ros-humble-image-publisher
apt-get install ros-humble-rqt
```

### Onboard
```bash
apt-get install ros-humble-robot-localization
```

## Testing Plan
Highlighting some general functionality that we need to cover in our testing plan. We will eventually write a GitHub issue for this.

### Landside

#### camera_view
1. Record bag from cameras using ROS2 bag cli. Add usage to the README
1. Run `bag_to_video` to convert the bag to an avi file, and verify that the feed looks correct
1. Run `video_to_bag` to convert the avi file back to a bag file. Note that the size should increase drastically due to frame padding, this is expected (use a small original bag file).
1. View stereo and mono camera feeds from landside while `avt_camera` is publishing. Update README to include new commands for viewing feeds.

#### joystick
1. Connect F310 joystick to the robot computer and run `F310.launch.py`. Verify that `joystick/raw` and `controls/desired_power` are receiving messages.
1. Connect Thrustmaster joystick to the robot computer and run `thrustmaster.launch.py`. Verify that `joystick/raw` and `controls/desired_power` are receiving messages.

#### simulation
1. Run `test_sim_comm.launch.py` in an empty scene and verify that there are no errors (the robot doesn't need to move in a square).
1. Run `test_sim_comm.launch,py` in a scene with an object (i.e. gate) and verify that `fake_cv_maker.py` works correctly.

### Onboard
#### acoustics
1. Run `acoustics.launch.py` in simulation and use the ROS2 action cli to generate some sample data. Verify that the results are expected.

#### avt_camera
1. Connect the left and right Allied Vision cameras to the robot computer and run `mono_camera` on both. Verify that the cameras connect and the corresponding topics are being published to (`camera/left/image_raw` and `camera/left/camera_info`)
1. Run `stereo_cameras.launch.py` and verify that all of the corresponding topics are being published.

#### controls
1. Run `controls.launch.py transform:=true` to verify that controls can be tested without simulation
1. Run `controls.launch.py sim:=true` while the simulation is running. Then run `test_state_publisher` with pose, velocity, and power control and verify that there are no errors (movement will probably be pretty bad).
1. Run `controls.launch.py` on the robot computer while `state.launch.py` is running. Verify that the robot moves.

#### cv
1. Move a test model to the `models` folder and rebuild the package.
1. Run `cv.launch.py` and `ros2 run cv test_images` and verify that the expected topics are published to without error. Note that `test_images` is currently configured to send images to the left camera topic.

#### data_pub
1. Run `pub_dvl.launch.py` and verify that the computer connects to the dvl. Verify that the `dvl/raw` and `dvl/odom` topics are being published to. Make sure the data is reasonable and the publishing rate is adequate.
1. Run `pub_imu.launch.py` and verify that the computer connects to the imu. Verify that the `sensors/imu/imu` and `sensors/imu/mag` topics are being published to. Make sure the data is reasonable and the publishing rate is adequate.
1. Run `pub_depth.launch.py` and verify that `offboard/pressure` is receiving values and `sensors/depth` is being published to. Make sure the data is reasonable and the publishing rate is adequate. This requires`offboard_comms` to be running to receive pressure sensor data from the Arduino.
1. Run `pub_all.launch.py` to make sure all of the sensors work together.

#### sensor_fusion
1. Run `fuse.launch.py` while the DVL and IMU are publishing. Verify that `/state` is published and has reasonable values.
1. Verify that we don't need to publish `robot_description` to get tf2 transforms. Our old documentation says that this is needed but I don't think this is the case anymore.

#### static_transforms
1. Run `static_transforms.launch.py` and verify that the correct transform values are being published.

#### system_utils
1. Run `system_info` and verify that the correct system usage messages are published.
1. Run `remote_launch` and verify that the `start_node` and `stop_node` services are created. Use the `ros2 service` cli to start and stop a test node and test launch file.
32 changes: 16 additions & 16 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ set -e
# Handle cleaning
if [[ "$1" == "clean" ]]; then
if [[ "$2" == "all" ]]; then
cd onboard/catkin_ws
catkin clean -y
cd onboard/ros2_ws
rm -r build install log
cd ../..
cd landside/catkin_ws
catkin clean -y
cd landside/ros2_ws
rm -r build install log
cd ../..
cd core/catkin_ws
catkin clean -y
cd core/ros2_ws
rm -r build install log
cd ../..
echo "clean all successful"
fi
if [[ -z "$2" ]]; then
cd "${COMPUTER_TYPE}"/catkin_ws
catkin clean -y
cd "${COMPUTER_TYPE}"/ros2_ws
rm -r build install log
cd ../..
echo "clean ${COMPUTER_TYPE} successful"
fi
Expand All @@ -34,21 +34,21 @@ if [[ -z "$COMPUTER_TYPE" ]]; then
fi

# shellcheck disable=SC1091
source /opt/ros/noetic/setup.bash
source /opt/ros/humble/setup.bash

echo "Building core workspace"
cd core/catkin_ws
catkin build
cd core/ros2_ws
colcon build
# shellcheck disable=SC1091
source devel/setup.bash
source install/setup.bash
cd ../..

echo "Building ${COMPUTER_TYPE} workspace"
cd "${COMPUTER_TYPE}"/catkin_ws
catkin build
cd "${COMPUTER_TYPE}"/ros2_ws
colcon build --symlink-install
# shellcheck disable=SC1091
source devel/setup.bash
source install/setup.bash
cd ../..

echo "If you did not source this scipt, please run"
echo "source ${COMPUTER_TYPE}/catkin_ws/devel/setup.bash"
echo "source ${COMPUTER_TYPE}/ros2_ws/install/setup.bash"
53 changes: 0 additions & 53 deletions core/catkin_ws/src/custom_msgs/CMakeLists.txt

This file was deleted.

Loading