diff --git a/.github/workflows/asan.yaml b/.github/workflows/asan.yaml index 2e450a40..2405709a 100644 --- a/.github/workflows/asan.yaml +++ b/.github/workflows/asan.yaml @@ -18,8 +18,8 @@ jobs: - name: build_and_test uses: ros-tooling/action-ros-ci@v0.2 env: - CC: clang -fsanitize-blacklist=/home/runner/work/blacklist.txt - CXX: clang++ -fsanitize-blacklist=/home/runner/work/blacklist.txt + CC: clang -fsanitize-blacklist=/home/runner/work/blacklist.txt -g3 + CXX: clang++ -fsanitize-blacklist=/home/runner/work/blacklist.txt -g3 with: target-ros2-distro: foxy # build all packages listed in the meta package diff --git a/rmf_traffic/CMakeLists.txt b/rmf_traffic/CMakeLists.txt index d5516187..24e4ae57 100644 --- a/rmf_traffic/CMakeLists.txt +++ b/rmf_traffic/CMakeLists.txt @@ -36,7 +36,6 @@ endif() find_package(rmf_utils REQUIRED) find_package(Eigen3 REQUIRED) -find_package(Threads) # ===== Traffic control library file(GLOB_RECURSE core_lib_srcs "src/rmf_traffic/*.cpp") @@ -46,6 +45,7 @@ add_library(rmf_traffic SHARED find_package(ament_cmake_catch2 QUIET) find_package(rmf_cmake_uncrustify QUIET) +find_package (Threads) if(BUILD_TESTING AND ament_cmake_catch2_FOUND AND rmf_cmake_uncrustify_FOUND) file(GLOB_RECURSE unit_test_srcs "test/*.cpp") diff --git a/rmf_traffic/include/rmf_traffic/reservations/Database.hpp b/rmf_traffic/include/rmf_traffic/reservations/Database.hpp new file mode 100644 index 00000000..5d34ebbb --- /dev/null +++ b/rmf_traffic/include/rmf_traffic/reservations/Database.hpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2020 Open Source Robotics Foundation + * + * 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. + * +*/ + +#ifndef RMF_TRAFFIC__DATABASE_HPP +#define RMF_TRAFFIC__DATABASE_HPP + +#include + +namespace rmf_traffic { +namespace reservations { + +class Database : public Writer +{ +public: + ///=========================================================================== + /// Documentation inherited from Writer + void register_participant( + ParticipantId id, + std::shared_ptr participant) override; + + ///=========================================================================== + /// Documentation inherited from Writer + void unregister_participant( + ParticipantId id + ) override; + + ///=========================================================================== + /// Documentation inherited from Writer + void request_reservation( + ParticipantId id, + RequestId req, + std::vector& request_options, + int priority = 0 + ) override; + + ///=========================================================================== + /// Documentation inherited from Writer + void cancel_request(ParticipantId id, RequestId req) override; + + Database(); + + class Implementation; +private: + rmf_utils::impl_ptr _pimpl; +}; + +} +} + +#endif diff --git a/rmf_traffic/include/rmf_traffic/reservations/Participant.hpp b/rmf_traffic/include/rmf_traffic/reservations/Participant.hpp new file mode 100644 index 00000000..2287f96a --- /dev/null +++ b/rmf_traffic/include/rmf_traffic/reservations/Participant.hpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020 Open Source Robotics Foundation + * + * 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. + * +*/ + +#ifndef RMF_TRAFFIC__PARTICIPANT_HPP +#define RMF_TRAFFIC__PARTICIPANT_HPP + +#include +#include +namespace rmf_traffic { +namespace reservations { + +using ParticipantId = uint64_t; + +///============================================================================= +/// \brief This class is used to handle the asynchronous callbacks made by the +/// database. In order to make a reservation you will need to inherit this class +class Participant +{ +public: + ///=========================================================================== + /// \brief This method is called whenever a change is proposed by the + /// reservation system to the participant. It is also called when you first + /// make a request. + /// \param[in] id is the RequestId of the request that will be impacted. + /// \param[in] res is the Reservation that is being proposed by the + /// reservation system. + /// \param[in] proposal_version is used to track the proposal's id + /// \return true if the request is acceptable, false otherwise. + virtual bool request_proposal( + RequestId id, + Reservation& res, + uint64_t proposal_version + ) = 0; + + ///=========================================================================== + /// \brief This is called when the solution to a request is confirmed. It will + /// only be called if all the participants that are impacted by the set of + /// changes needed have approved of it. Note: once this has been called it is + /// expected that the participant will comply. + /// \param[in] id the request id. + /// \param[in] res the response. + /// \param[in] proposal_version is used to track the proposal's id + /// \return true if the request has been successfully confirmed, false + /// otherwise + virtual bool request_confirmed( + RequestId id, + Reservation& res, + uint64_t proposal_version + ) = 0; + + ///=========================================================================== + /// \brief This method is called whenever a change is proposed by the + /// reservation system to the participant to cancel the request made by it. + /// The request will still remain in the database, just that it will be + /// serviced at some point later if possible. + /// \param[in] id is the RequestId of the request that will be impacted. + /// \param[in] proposal_version is used to track the proposal's id + /// \return true if the you agree to allow your request to be cancelled, false + /// otherwise. + virtual bool unassign_request_confirmed( + RequestId id, + uint64_t proposal_version + ) = 0; + + ///=========================================================================== + /// \brief This method is called whenever a cancellation has been allowed. + /// \param[in] id is the RequestId of the request that will be impacted. + /// \param[in] proposal_version is used to track the proposal's id + /// \return true if the request is acceptable, false otherwise. + virtual bool unassign_request_proposal( + RequestId id, + uint64_t proposal_version + ) = 0; +}; + +} +} +#endif diff --git a/rmf_traffic/include/rmf_traffic/reservations/Reservation.hpp b/rmf_traffic/include/rmf_traffic/reservations/Reservation.hpp new file mode 100644 index 00000000..3cf9ee82 --- /dev/null +++ b/rmf_traffic/include/rmf_traffic/reservations/Reservation.hpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2021 Open Source Robotics Foundation + * + * 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. + * +*/ + +#ifndef RMF_TRAFFIC__RESERVATIONS_HPP +#define RMF_TRAFFIC__RESERVATIONS_HPP + +#include +#include +#include +#include +#include + +namespace rmf_traffic { +namespace reservations { + +using ReservationId = uint64_t; +//============================================================================== +/// \brief The Reservation class represents a proposed solution to a given +/// ReservationRequest. +class Reservation +{ +public: + + ///=========================================================================== + /// \brief The time at which the Reservation will start. + const rmf_traffic::Time start_time() const; + + ///=========================================================================== + /// \brief The minimum duration of the Reservation. + const std::optional duration() const; + + ///=========================================================================== + /// \brief The earliest finish time + const std::optional finish_time() const; + + ///=========================================================================== + /// \brief Shifts the actual finish time + void set_actual_finish_time(rmf_traffic::Time dur); + + ///=========================================================================== + /// \brief creates a new reservation with a different finish time based on + /// this reservation. + Reservation propose_new_finish_time(rmf_traffic::Time dur); + + ///=========================================================================== + /// \brief creates a new reservation with a different start time based on + /// this reservation. + Reservation propose_new_start_time(rmf_traffic::Time dur); + + ///=========================================================================== + /// \brief Returns true if the reservation is indefinite. An indefinite + /// reservation has no duration or finish time. + bool is_indefinite() const; + + ///=========================================================================== + /// \brief Returns the actual finish time of the reservation. If the + /// reservation is indefinite then it returns a `std::nullopt`. + const std::optional actual_finish_time() const; + + ///=========================================================================== + /// \brief Returns the resource which is being reserved by the reservation. + const std::string resource_name() const; + + ///=========================================================================== + /// \brief Returns a reservation id. Used internally to + ReservationId reservation_id() const; + + ///=========================================================================== + /// \brief Returns true if two reservations are overlapping. + bool conflicts_with(const Reservation& other) const; + + ///=========================================================================== + /// \brief Checks equality of two reservations. Note: reservation ids are not + /// compared. + bool operator==(const Reservation& other) const; + + ///=========================================================================== + /// \brief Checks inequality of two reservations. Note: reservation ids are + /// not compared. + bool operator!=(const Reservation& other) const; + + ///=========================================================================== + /// \brief Creates a reservation. + /// \param[in] start_time The time at which the reservation will start. + /// \param[in] resource_name The name of the resource which is being reserved. + /// \param[in] duration The minimum duration of the reservation. + /// \param[in] finish_time The earliest finish time. + /// Note: If both `duration` and `finish_time` are `std::nullopt` then the + /// reservation is indefinite. If both `duration` and `finish_time` are not + /// `std::nullopt` then the actual finish time is + /// $max(finish_time, start_time + duration)$ + static Reservation make_reservation( + rmf_traffic::Time start_time, + std::string resource_name, + std::optional duration, + std::optional finish_time); + + class Implementation; + + ///=========================================================================== + /// \brief Constructor + Reservation(); + +private: + rmf_utils::impl_ptr _pimpl; +}; +} // end namespace reservations +} // end namespace rmf_traffic +#endif diff --git a/rmf_traffic/include/rmf_traffic/reservations/ReservationRequest.hpp b/rmf_traffic/include/rmf_traffic/reservations/ReservationRequest.hpp new file mode 100644 index 00000000..9f0a0a94 --- /dev/null +++ b/rmf_traffic/include/rmf_traffic/reservations/ReservationRequest.hpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2020 Open Source Robotics Foundation + * + * 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. + * +*/ + +#ifndef RMF_TRAFFIC__RESERVATION_REQUEST_HPP +#define RMF_TRAFFIC__RESERVATION_REQUEST_HPP + +#include +#include +#include +#include +#include + +namespace rmf_traffic { +namespace reservations { + +using RequestId = uint64_t; + +///============================================================================= +/// \brief This class represents a reservation request. +class ReservationRequest +{ + +public: + ///=========================================================================== + /// \brief Time range for describing the starting time. The starting time may + /// either have a lower bound, upper bound, both or none. This constraints the + /// possible starting times for a given reservation. + class TimeRange + { + public: + const std::optional