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

Feature/mw/fields2cover2 #53

Open
wants to merge 73 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
c81ba02
Fix BT.CPP upgrade
tonynajjar Mar 5, 2024
2688106
Bug fixes
tonynajjar Mar 5, 2024
0841d1d
Update opennav_coverage/src/visualizer.cpp
SteveMacenski Mar 5, 2024
4cbdcc7
add readme
tonynajjar Mar 5, 2024
06497c7
fix flake8
tonynajjar Mar 5, 2024
62d628a
building fixes
tonynajjar Mar 5, 2024
3669e7d
testing with rolling
tonynajjar Mar 5, 2024
a3948ec
Revert "testing with rolling"
tonynajjar Mar 5, 2024
2d48105
test with rolling
tonynajjar Mar 6, 2024
b85696b
Merge remote-tracking branch 'origin/main'
tonynajjar Mar 7, 2024
99eadcf
Add BTCPP_format="4" to trees
tonynajjar Mar 7, 2024
aa2cf20
Use tree_->haltTree();
tonynajjar Mar 7, 2024
668abc4
Revert "Use tree_->haltTree();"
tonynajjar Mar 14, 2024
1934a78
Revert "Revert "Use tree_->haltTree();""
tonynajjar Mar 14, 2024
4767882
Update to fields2Cover v2.0.0 api
aosmw Apr 24, 2024
9c34271
Add dependency on ortools_vendor
aosmw Apr 29, 2024
4c401d0
Port opennav_row_coverage to fields2cover v2
aosmw Apr 29, 2024
e2d89e1
opennav_coverage: workaround non ament packaged Fields2Cover
aosmw Apr 29, 2024
35b0ce5
opennav_coverage - fix tests for fields2cover v2
aosmw Apr 29, 2024
c770d45
Revert addition of ortools_vendor to deps.repos
aosmw May 3, 2024
a221d67
Remove unnecessary comment
aosmw May 3, 2024
9c1ccfb
Revert addition of navigation2 to deps.repos
aosmw May 3, 2024
fbbcca1
Revert addition of ortools_vendor
aosmw May 3, 2024
0590d7d
uncrustify
aosmw May 3, 2024
10758ad
Remove default_turn_point_distance == Discretization comment
aosmw May 3, 2024
1b0cb2b
cpplint/uncrustify style line lenght if/else style
aosmw May 4, 2024
363415d
Add gitignore; Add rviz config; (#51)
DeccanLin Apr 22, 2024
9a38dc4
demo rviz coverage_plan/coverage_plan Transient Local
aosmw May 4, 2024
ed382a4
Put navigation2 back into .github/deps.repos for nav_msgs
aosmw May 6, 2024
d44f82c
DO NOT MERGE - temporarily pointing at aosmw fork of Fields2Cover
aosmw May 6, 2024
619b528
ci - attempt workaround rosdep not providing geometry_msgs
aosmw May 7, 2024
8486ed0
ci - attempt workaround rosdep not providing rosidl_default_generators
aosmw May 7, 2024
be161da
ci = guess a better base image that already has rclcpp in it
aosmw May 7, 2024
ba3a6c9
ci - install geographic_msgs
aosmw May 7, 2024
4628bf3
Fix spelling of geographic_msgs package
aosmw May 7, 2024
7649af9
ci - install bondcpp and angles
aosmw May 7, 2024
3de3c4e
Use ros-tooling/[email protected], rosdep-check: true, add test_msgs
aosmw May 7, 2024
47d0890
ros-tooling/[email protected] not found go back to v0.3
aosmw May 7, 2024
54b19a5
ci - install behaviortree_cpp
aosmw May 7, 2024
33490ee
Install diagnostic-updater
aosmw May 7, 2024
c30abd3
Try to get this to work with act(Run github actions locally).
aosmw May 7, 2024
eb1488c
More ci dependencies for nav2 build
aosmw May 8, 2024
77d1c94
ci - fix laser_geometry package name
aosmw May 9, 2024
2db2ce9
ci - nav2 contrained smoother wants libceres-dev
aosmw May 9, 2024
d9c63ed
ci - try libunwind-dev to try to get libgoogle-glog-dev to be happy f…
aosmw May 9, 2024
e14194f
ci - need robot-localization
aosmw May 9, 2024
6d4e370
Build and test only what is necessary for this repo
aosmw May 12, 2024
5062803
Attempt build on noble, remove rosdep-check: true which doesn't perfo…
aosmw May 13, 2024
fe41c6b
Add separate jammy rolling action
aosmw May 13, 2024
6a00d89
Try removing python3-nose
aosmw May 13, 2024
ffcb2e3
Try running apt-get update to get latest python3-rosdep
aosmw May 13, 2024
ec7ab9d
pip uninstall nose
aosmw May 14, 2024
6499975
Fix apt update, use PIP_BREAK_SYSTEM_PACKAGES=1 for pip command
aosmw May 14, 2024
d2b9fd0
fix PIP_BREAK_SYSTEM_PACKAGES env var
aosmw May 14, 2024
148c84a
more worflow
aosmw May 14, 2024
01d5171
workflow
aosmw May 14, 2024
f73d34d
Attempt to manipulate rosdep index for jammy back to Feb 28,2024
aosmw May 14, 2024
c4e9359
Try single quotes for sed
aosmw May 14, 2024
89821d3
action syntax
aosmw May 14, 2024
ff68d03
action syntax sed
aosmw May 14, 2024
36b818b
Run through yamllint
aosmw May 14, 2024
c9d4bf4
Adjust noble_rolling to use pre-release binaries
aosmw May 14, 2024
795800c
noble_rolling needs libyaml-cpp-dev rosdep problem?
aosmw May 14, 2024
11e8e1a
jammy_rolling: workaround libgoogle-glog-dev libunwind-dev libceres-dev
aosmw May 14, 2024
51b714e
Abandon rolling on jammy
aosmw May 30, 2024
f213e2f
Strip away build on influx rolling workarounds
aosmw May 30, 2024
a4f275e
Comment out fields2cover from deps.repos, attempt to build against pa…
aosmw May 30, 2024
02ee9c0
gh action: install nodejs for local build nektos/act
aosmw Jun 3, 2024
8496db1
Build fields2cover from source again
aosmw Jun 3, 2024
50f4758
nav2_constrained_smoother has conflicted libunwind-dev, libgoogle-glo…
aosmw Jun 3, 2024
43748b2
Add ortools_vendor to deps.repos
aosmw May 30, 2024
6539b0a
Ignore vim .swp files
aosmw Jun 13, 2024
9d1ad83
deps.repos lock to tags for ortools_vendor and Fields2Cover
aosmw Jun 13, 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
12 changes: 10 additions & 2 deletions .github/deps.repos
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
repositories:
Fields2Cover:
navigation2:
type: git
url: https://github.com/Fields2Cover/Fields2Cover.git
url: https://github.com/ros-navigation/navigation2.git
version: main
fields2cover:
type: git
url: https://github.com/aosmw/Fields2Cover.git
version: 9c3c352ba1dc71f3f48706c298b82cd4641e536e
ortools_vendor:
type: git
url: https://github.com/Fields2Cover/ortools_vendor.git
version: c28f53e50164645fa8cee0a7a307061ac6f83aa7
54 changes: 36 additions & 18 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
---
name: Test
on:
pull_request:
Expand All @@ -6,29 +7,46 @@ on:
- main

jobs:
build_and_test:
noble_rolling:
runs-on: ubuntu-latest
env:
ROS_DISTRO: ${{ matrix.ros_distro }}
RMW_IMPLEMENTATION: rmw_cyclonedds_cpp
container:
image: rostooling/setup-ros-docker:ubuntu-jammy-latest
image: rostooling/setup-ros-docker:ubuntu-noble-ros-rolling-ros-base-latest
strategy:
fail-fast: false
matrix:
ros_distro: [iron]
ros_distro: [rolling]
steps:
- uses: actions/checkout@v2
- name: Install Cyclone DDS
run: sudo apt install ros-${{ matrix.ros_distro }}-rmw-cyclonedds-cpp -y
- name: Build and run tests
id: action-ros-ci
uses: ros-tooling/[email protected]
with:
import-token: ${{ secrets.GITHUB_TOKEN }}
target-ros2-distro: ${{ matrix.ros_distro }}
vcs-repo-file-url: "${{ github.workspace }}/.github/deps.repos"
- uses: actions/upload-artifact@v1
with:
name: colcon-logs
path: ros_ws/log
- name: Install node, libunwind-dev, libgoogle-glog-dev
run: |
sudo apt-get update
sudo apt-get -y install nodejs
sudo apt-get -y install libunwind-dev
sudo apt-get -y install libgoogle-glog-dev
sudo apt-get -y install libceres-dev
- name: checkout source
uses: actions/checkout@v4
- name: Build and run tests
id: action-ros-ci
uses: ros-tooling/[email protected]
with:
package-name: "opennav_coverage_demo"
target-ros2-distro: ${{ matrix.ros_distro }}
vcs-repo-file-url: "${{ github.workspace }}/.github/deps.repos"
colcon-defaults: |
{
"test": {
"packages-select": [
"opennav_coverage",
"opennav_coverage_bt",
"opennav_row_coverage",
"opennav_coverage_navigator",
"opennav_coverage_demo"
]
}
}
- uses: actions/upload-artifact@v1
with:
name: noble-colcon-logs
path: ros_ws/log
59 changes: 59 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
*.pch

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Fortran module files
*.mod
*.smod

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app

# Colcon output
build
log
install

# Visual Studio Code files
.vscode

# Eclipse project files
.cproject
.project
.pydevproject

# Python artifacts
__pycache__/
*.py[cod]
.ipynb_checkpoints

sphinx_doc/_build

# CLion artifacts
.idea
cmake-build-debug/

# doxygen docs
doc/html/

#Vim
*.swp
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Open Navigation's Nav2 Complete Coverage

This package contains the Complete Coverage Task Server & auxiliary tools utilizing the [Fields2Cover](https://github.com/Fields2Cover/Fields2Cover) complete coverage planning system which includes a great deal of options in headland, swath, route, and final path planning. You can find more information about Fields2Cover (F2C) in its [ReadTheDocs Documentation](https://fields2cover.github.io/index.html). It can accept both GPS and Cartesian coordinates and publishes the field, headland, swaths, and route as separate topics in cartesian coordinates for debugging and visualization. It can also compute coverage paths based on open-field polygons **or** based on annotated rows as might exist in a tree farm or other applications with both irregular and regular pre-established rows.
This package contains the Complete Coverage Task Server & auxiliary tools utilizing the [Fields2Cover](https://github.com/Fields2Cover/Fields2Cover) complete coverage planning system which includes a great deal of options in headland, swath, route, and final path planning. You can find more information about Fields2Cover (F2C) in its [ReadTheDocs Documentation](https://fields2cover.github.io/index.html). It can accept both GPS and Cartesian coordinates and publishes the field, headland, swaths, and route as separate topics in cartesian coordinates for debugging and visualization (topics have Transient Local durability for late-joining visualization tools). It can also compute coverage paths based on open-field polygons **or** based on annotated rows as might exist in a tree farm or other applications with both irregular and regular pre-established rows.

This capability was created by [Open Navigation LLC](https://www.opennav.org/) in partnership with [Bonsai Robotics](https://www.bonsairobotics.ai/). Bonsai Robotics builds autonomous software for machines in adverse and GPS degraded conditions utilizing vision. Bonsai Robotics funded the development of this work for their own product and has graciously allowed Open Navigation to open-source it for the community to leverage in their own systems. Please thank Bonsai Robotics for their commendable donation to the ROS community! Bonsai is hiring [here](https://www.bonsairobotics.ai/careers).

Expand Down
2 changes: 2 additions & 0 deletions opennav_coverage/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.5)
project(opennav_coverage)

find_package(ament_cmake REQUIRED)
find_package(ament_index_cpp REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_action REQUIRED)
find_package(rclcpp_lifecycle REQUIRED)
Expand Down Expand Up @@ -42,6 +43,7 @@ set(dependencies
builtin_interfaces
tf2_ros
opennav_coverage_msgs
ament_index_cpp
)

add_library(${library_name} SHARED
Expand Down
14 changes: 7 additions & 7 deletions opennav_coverage/include/opennav_coverage/robot_params.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,19 @@ class RobotParams
{
nav2_util::declare_parameter_if_not_declared(
node, "robot_width", rclcpp::ParameterValue(2.1));
robot_.robot_width = node->get_parameter("robot_width").as_double();
robot_.setWidth(node->get_parameter("robot_width").as_double());

nav2_util::declare_parameter_if_not_declared(
node, "operation_width", rclcpp::ParameterValue(2.5));
robot_.op_width = node->get_parameter("operation_width").as_double();
robot_.setCovWidth(node->get_parameter("operation_width").as_double());

nav2_util::declare_parameter_if_not_declared(
node, "min_turning_radius", rclcpp::ParameterValue(0.4));
robot_.setMinRadius(node->get_parameter("min_turning_radius").as_double());
robot_.setMinTurningRadius(node->get_parameter("min_turning_radius").as_double());

nav2_util::declare_parameter_if_not_declared(
node, "linear_curv_change", rclcpp::ParameterValue(2.0));
robot_.linear_curv_change = node->get_parameter("linear_curv_change").as_double();
robot_.setMaxDiffCurv(node->get_parameter("linear_curv_change").as_double());
}

/**
Expand All @@ -65,16 +65,16 @@ class RobotParams
*/
double getWidth()
{
return robot_.robot_width;
return robot_.getWidth();
}

/**
* @brief Get the robot's operational width
* @brief Get the robot's operational/coverage width
* @return robot's operational width in m
*/
double getOperationWidth()
{
return robot_.op_width;
return robot_.getCovWidth();
}

/**
Expand Down
61 changes: 31 additions & 30 deletions opennav_coverage/include/opennav_coverage/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ inline opennav_coverage_msgs::msg::PathComponents toCoveragePathMsg(
msg.swaths_ordered = true;
msg.header = header;

if (raw_path.states.size() == 0) {
if (raw_path.size() == 0) {
return msg;
}

Expand All @@ -142,54 +142,55 @@ inline opennav_coverage_msgs::msg::PathComponents toCoveragePathMsg(
path.moveTo(field.getRefPoint());
}

PathSectionType curr_state = path.states[0].type;
if (curr_state == PathSectionType::SWATH) {
curr_swath_start = path.states[0].point;
} else if (curr_state == PathSectionType::TURN) {
PathSectionType curr_section_type = path.getState(0).type;
if (curr_section_type == PathSectionType::SWATH) {
curr_swath_start = path.getState(0).point;
} else if (curr_section_type == PathSectionType::TURN) {
msg.turns.push_back(nav_msgs::msg::Path());
msg.turns.back().header = header;
curr_turn = &msg.turns.back();
}

for (unsigned int i = 0; i != path.states.size(); i++) {
if (curr_state == path.states[i].type && path.states[i].type == PathSectionType::SWATH) {
for (unsigned int i = 0; i != path.size(); i++) {
auto idx_type = path.getState(i).type;
if (curr_section_type == idx_type && idx_type == PathSectionType::SWATH) {
// Continuing swath so...
// (1) no action required.
} else if (curr_state == path.states[i].type && path.states[i].type == PathSectionType::TURN) {
} else if (curr_section_type == idx_type && idx_type == PathSectionType::TURN) {
// Continuing a turn so...
// (1) keep populating
curr_turn->poses.push_back(toMsg(path.states[i]));
} else if (curr_state != path.states[i].type && path.states[i].type == PathSectionType::TURN) {
curr_turn->poses.push_back(toMsg(path.getState(i)));
} else if (curr_section_type != idx_type && idx_type == PathSectionType::TURN) {
// Transitioning from a swath to a turn so...
// (1) Complete the existing swath
opennav_coverage_msgs::msg::Swath swath;
swath.start = toMsg(curr_swath_start);
swath.end = toMsg(path.states[i - 1].point);
swath.end = toMsg(path.getState(i - 1).point);
msg.swaths.push_back(swath);
// (2) Start a new turn path
msg.turns.push_back(nav_msgs::msg::Path());
msg.turns.back().header = header;
curr_turn = &msg.turns.back();
curr_turn->poses.push_back(toMsg(path.states[i]));
} else if (curr_state != path.states[i].type && path.states[i].type == PathSectionType::SWATH) {
curr_turn->poses.push_back(toMsg(path.getState(i)));
} else if (curr_section_type != idx_type && idx_type == PathSectionType::SWATH) {
// Transitioning from a turn to a swath so...
// (1) Update new swath starting point
curr_swath_start = path.states[i].point;
curr_swath_start = path.getState(i).point;
}

curr_state = path.states[i].type;
curr_section_type = idx_type;

if (path.states[i].type != PathSectionType::SWATH &&
path.states[i].type != PathSectionType::TURN)
if (idx_type != PathSectionType::SWATH &&
idx_type != PathSectionType::TURN)
{
throw std::runtime_error("Unknown type of path state detected, cannot obtain path!");
}
}

if (curr_state == PathSectionType::SWATH) {
if (curr_section_type == PathSectionType::SWATH) {
opennav_coverage_msgs::msg::Swath swath;
swath.start = toMsg(curr_swath_start);
swath.end = toMsg(path.states.back().point);
swath.end = toMsg(path.back().point);
msg.swaths.push_back(swath);
}

Expand All @@ -215,7 +216,7 @@ inline nav_msgs::msg::Path toNavPathMsg(
nav_msgs::msg::Path msg;
msg.header = header;

if (raw_path.states.size() == 0) {
if (raw_path.size() == 0) {
return msg;
}

Expand All @@ -226,15 +227,15 @@ inline nav_msgs::msg::Path toNavPathMsg(
path.moveTo(field.getRefPoint());
}

for (unsigned int i = 0; i != path.states.size(); i++) {
for (unsigned int i = 0; i != path.size(); i++) {
// Swaths come in pairs of start-end sequentially
if (i > 0 && path.states[i].type == PathSectionType::SWATH &&
path.states[i - 1].type == PathSectionType::SWATH)
if (i > 0 && path.getState(i).type == PathSectionType::SWATH &&
path.getState(i - 1).type == PathSectionType::SWATH)
{
const float & x0 = path.states[i - 1].point.getX();
const float & y0 = path.states[i - 1].point.getY();
const float & x1 = path.states[i].point.getX();
const float & y1 = path.states[i].point.getY();
const float & x0 = path.getState(i - 1).point.getX();
const float & y0 = path.getState(i - 1).point.getY();
const float & x1 = path.getState(i).point.getX();
const float & y1 = path.getState(i).point.getY();

const float dist = hypotf(x1 - x0, y1 - y0);
const float ux = (x1 - x0) / dist;
Expand All @@ -243,10 +244,10 @@ inline nav_msgs::msg::Path toNavPathMsg(

geometry_msgs::msg::PoseStamped pose;
pose.pose.orientation =
nav2_util::geometry_utils::orientationAroundZAxis(path.states[i].angle);
nav2_util::geometry_utils::orientationAroundZAxis(path.getState(i).angle);
pose.pose.position.x = x0;
pose.pose.position.y = y0;
pose.pose.position.z = path.states[i].point.getZ();
pose.pose.position.z = path.getState(i).point.getZ();

while (curr_dist < dist) {
pose.pose.position.x += pt_dist * ux;
Expand All @@ -256,7 +257,7 @@ inline nav_msgs::msg::Path toNavPathMsg(
}
} else {
// Turns are already dense paths
msg.poses.push_back(toMsg(path.states[i]));
msg.poses.push_back(toMsg(path.getState(i)));
}
}

Expand Down
8 changes: 4 additions & 4 deletions opennav_coverage/include/opennav_coverage/visualizer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ class Visualizer
{
nav_plan_pub_ = rclcpp::create_publisher<nav_msgs::msg::Path>(
node->get_node_topics_interface(),
"coverage_server/coverage_plan", rclcpp::QoS(1));
"coverage_server/coverage_plan", rclcpp::QoS(1).transient_local());
SteveMacenski marked this conversation as resolved.
Show resolved Hide resolved
headlands_pub_ = rclcpp::create_publisher<geometry_msgs::msg::PolygonStamped>(
node->get_node_topics_interface(),
"coverage_server/field_boundary", rclcpp::QoS(1));
"coverage_server/field_boundary", rclcpp::QoS(1).transient_local());
planning_field_pub_ = rclcpp::create_publisher<geometry_msgs::msg::PolygonStamped>(
node->get_node_topics_interface(),
"coverage_server/planning_field", rclcpp::QoS(1));
"coverage_server/planning_field", rclcpp::QoS(1).transient_local());
swaths_pub_ = rclcpp::create_publisher<visualization_msgs::msg::Marker>(
node->get_node_topics_interface(),
"coverage_server/swaths", rclcpp::QoS(1));
"coverage_server/swaths", rclcpp::QoS(1).transient_local());
}

void deactivate();
Expand Down
Loading
Loading