Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 43 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: CI

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

defaults:
run:
shell: bash

env:
DEBIAN_FRONTEND: noninteractive

jobs:
build:
name: Ubuntu ${{ matrix.ubuntu }} (${{ matrix.arch }})
runs-on: ${{ matrix.runner }}
container: ubuntu:${{ matrix.ubuntu }}
strategy:
fail-fast: false
matrix:
ubuntu: ["24.04", "26.04"]
arch: [amd64, arm64]
include:
- arch: amd64
runner: ubuntu-24.04
- arch: arm64
runner: ubuntu-24.04-arm
steps:
# Without git, actions/checkout downloads an archive, and init.sh can't check out the submodules
- name: Install git
run: apt-get update && apt-get install -y --no-install-recommends ca-certificates git
- uses: actions/checkout@v5
- name: Install dependencies
run: |
git config --global --add safe.directory '*'
./init.sh
- name: Build
run: ./build.sh
- name: Test
run: ctest --test-dir build --output-on-failure --no-tests=error
7 changes: 7 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[submodule "external/openocean-messages"]
path = external/openocean-messages
url = https://github.com/openocean-software/openocean-messages.git
[submodule "external/moos-ivp"]
path = external/moos-ivp
url = https://github.com/GobySoft/moos-ivp.git
shallow = true
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@ endif()

set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")

# MOOS-IvP's helm libraries (IVP_BUILD_HELM_LIBS_ONLY)
find_package(IVP CONFIG REQUIRED)

include(CTest)

add_subdirectory(src)
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,26 @@ One way to think of this project is as a generator for the equivalent of the MOO
- bin: Binary source
- goby: Goby middleware app
- ros: ROS middleware node
- external: Submodules
- openocean-messages: [openocean-messages](https://github.com/openocean-software/openocean-messages), for the `Navigation` and `ControlSetpoint` messages
- moos-ivp: [MOOS-IvP](https://github.com/GobySoft/moos-ivp), for the IvP solver and behaviors

## Building

*This section was written by Claude.*

The interface messages use `Navigation` and `ControlSetpoint` from [openocean-messages](https://github.com/openocean-software/openocean-messages), found with `find_package(openocean_messages)`: install it, or point CMake at its build directory:
`init.sh` checks out the submodules and installs the Ubuntu packages needed to build them and IvPico. `build.sh` then builds, all in `build/`:

- openocean-messages, into `build/external/openocean-messages`;
- MOOS-IvP's helm libraries (`IVP_BUILD_HELM_LIBS_ONLY`, as shared libraries, without MOOS or its apps), into `build/external/moos-ivp`, installed into `build/external/install` for `find_package(IVP)`;
- IvPico, against both.

```
cmake -S . -B build -Dopenocean_messages_DIR=/path/to/openocean-messages/build
cmake --build build
./init.sh
./build.sh
ctest --test-dir build
```

`build.sh` passes any arguments on to IvPico's CMake, and `BUILD_DIR` overrides the build directory.

To update a submodule, check out the commit you want in it and commit the new pointer, e.g. `git -C external/openocean-messages pull origin main && git add external/openocean-messages`.
34 changes: 34 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
# Builds the dependencies from their submodules (openocean-messages, and MOOS-IvP's helm libraries),
# then IvPico against them, all in BUILD_DIR (default build). Arguments are passed on to IvPico's
# cmake.
set -euo pipefail

cd "$(dirname "$0")"
for submodule in openocean-messages moos-ivp; do
if [ -z "$(ls -A "external/${submodule}")" ]; then
echo "external/${submodule} is empty: run ./init.sh first" >&2
exit 1
fi
done
BUILD_DIR=$(realpath -m "${BUILD_DIR:-build}")
OPENOCEAN_BUILD_DIR=${BUILD_DIR}/external/openocean-messages
IVP_BUILD_DIR=${BUILD_DIR}/external/moos-ivp
# find_package(IVP) only works from an installation
IVP_INSTALL_DIR=${BUILD_DIR}/external/install

BUILD_DIR=${OPENOCEAN_BUILD_DIR} external/openocean-messages/build.sh -DBUILD_TESTING=OFF

cmake -S external/moos-ivp/ivp/src -B "${IVP_BUILD_DIR}" -G Ninja \
-DIVP_BUILD_HELM_LIBS_ONLY=ON -DBUILD_SHARED_LIBS=ON \
-DIVP_LIB_DIRECTORY="${IVP_BUILD_DIR}/lib" \
-DIVP_INC_DIRECTORY="${IVP_BUILD_DIR}/include" \
-DIVP_BIN_DIRECTORY="${IVP_BUILD_DIR}/bin"
ninja -C "${IVP_BUILD_DIR}"
cmake --install "${IVP_BUILD_DIR}" --prefix "${IVP_INSTALL_DIR}" > /dev/null

cmake -S . -B "${BUILD_DIR}" -G Ninja \
-Dopenocean_messages_DIR="${OPENOCEAN_BUILD_DIR}" \
-DIVP_DIR="${IVP_INSTALL_DIR}/lib/cmake/IVP" \
"$@"
ninja -C "${BUILD_DIR}"
1 change: 1 addition & 0 deletions external/moos-ivp
Submodule moos-ivp added at be40e2
1 change: 1 addition & 0 deletions external/openocean-messages
Submodule openocean-messages added at 11a132
33 changes: 33 additions & 0 deletions init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
# Checks out the submodules and installs the Ubuntu packages needed to build them and IvPico.
#
# Usage: init.sh
set -euo pipefail

cd "$(dirname "$0")"

case "${1:-}" in
"") ;;
-h | --help)
sed -n '4p' "$0" | sed 's/^# //'
exit 0
;;
*)
sed -n '4p' "$0" | sed 's/^# //' >&2
exit 1
;;
esac

git submodule update --init --recommend-shallow

SUDO=""
if [ "$(id -u)" -ne 0 ]; then
SUDO=sudo
fi

# moos-ivp's helm libraries (IVP_BUILD_HELM_LIBS_ONLY) need only CMake and a compiler
packages=(cmake ninja-build g++ git ca-certificates protobuf-compiler libprotobuf-dev)
$SUDO apt-get update
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${packages[@]}"

external/openocean-messages/init.sh --cxx
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
add_subdirectory(lib)
add_subdirectory(bin)

if(BUILD_TESTING)
add_subdirectory(test)
endif()
3 changes: 3 additions & 0 deletions src/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_executable(check_helm_libs check_helm_libs.cpp)
target_link_libraries(check_helm_libs PRIVATE IVP::helmivp IVP::ivpbuild IVP::ivpsolve IVP::ivpcore)
add_test(NAME helm_libs COMMAND check_helm_libs)
59 changes: 59 additions & 0 deletions src/test/check_helm_libs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Checks that IvPico can use MOOS-IvP's helm libraries (external/moos-ivp, built by build.sh):
//
// 1. The static behavior factory creates behaviors from lib_behaviors-marine
// and lib_behaviors-colregs, which loads every helm library.
// 2. The IvP solver finds the peak of a one-function problem over course.
//
// Prints one line per problem and exits non-zero if there were any.

#include <cmath>
#include <iostream>
#include <string>

#include "BFactoryStatic.h"
#include "IvPBehavior.h"
#include "IvPDomain.h"
#include "IvPProblem.h"
#include "ZAIC_PEAK.h"

int main()
{
int errors = 0;

IvPDomain domain;
domain.addDomain("course", 0, 359, 360);
domain.addDomain("speed", 0, 4, 41);

BFactoryStatic factory;
factory.setDomain(domain);
for (const std::string type : {"BHV_Waypoint", "BHV_AvdColregsV22"})
{
IvPBehavior* behavior = factory.newBehavior(type);
if (!behavior)
{
std::cerr << "failed: no " << type << " from BFactoryStatic\n";
++errors;
}
delete behavior;
}

IvPDomain course;
course.addDomain("course", 0, 359, 360);
ZAIC_PEAK zaic(course, "course");
zaic.setSummit(90);
zaic.setBaseWidth(90);
zaic.setValueWrap(true);

IvPProblem problem;
problem.setDomain(course);
problem.addOF(zaic.extractIvPFunction());
problem.solve();
const double result = problem.getResult("course");
if (std::fabs(result - 90) > 1)
{
std::cerr << "failed: solved course " << result << ", not 90\n";
++errors;
}

return errors == 0 ? 0 : 1;
}