Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
bbf46f2
first pass navigation hpp
abe-winter Nov 13, 2024
a270b0d
missing include
abe-winter Nov 13, 2024
e338601
green
abe-winter Nov 13, 2024
e8e2aab
checkpoint
abe-winter Nov 13, 2024
4783dd6
proto constructors, unique_ptr
abe-winter Nov 14, 2024
0cb6b02
nav client compiles
abe-winter Nov 14, 2024
2deaf73
nav service compiles, register it
abe-winter Nov 14, 2024
6c8545d
clang format
abe-winter Nov 14, 2024
3b83c1b
extra nav mentions where needed in cmake
abe-winter Nov 14, 2024
f353325
sigh clang-tidy
abe-winter Nov 14, 2024
1f51fa8
vec <-> repeated pointer converters in utils
abe-winter Nov 14, 2024
3960542
use builtin types instead of protos
abe-winter Nov 14, 2024
b7c8cb5
clang format grr
abe-winter Nov 14, 2024
3f7c6c7
add inlines without
abe-winter Nov 14, 2024
d36b9ea
instead of constructor + operator, weird not-quite-sfinae approach to…
abe-winter Nov 14, 2024
2f470be
lint
abe-winter Nov 14, 2024
d334572
clear destination in ptr <-> vec conversions
abe-winter Nov 14, 2024
d640587
actually remove proto headers from nav wrapper
abe-winter Nov 14, 2024
b674f55
nolints
abe-winter Nov 14, 2024
49b210b
clang format
abe-winter Nov 14, 2024
d5e7d3a
get rid of annoying template approach
abe-winter Nov 15, 2024
aa5e1f0
fix comments
abe-winter Nov 15, 2024
359d53b
move proto_utils to private
abe-winter Nov 15, 2024
3def54d
nested namespaces only in cpp17
abe-winter Nov 15, 2024
226d860
remove name param, other sdks don't use it in nav wrappers
abe-winter Nov 16, 2024
83444b3
properties struct instead of returning raw maptype in case we add mor…
abe-winter Nov 16, 2024
305e2a8
mock and test stubs
abe-winter Nov 16, 2024
0128a00
roundtrip test passing
abe-winter Nov 16, 2024
679432c
operator==, fix type on NavServer::DoCommand
abe-winter Nov 16, 2024
6631bc0
test all methods
abe-winter Nov 16, 2024
d4cf2e7
docstrings
abe-winter Nov 16, 2024
c6d5da9
Merge branch 'main' into aw-nav-service
abe-winter Nov 16, 2024
7fa6630
missing const
abe-winter Nov 16, 2024
4e9f32c
x_from_proto -> from_proto
abe-winter Nov 18, 2024
6c26a8c
change mapOver signature
abe-winter Nov 18, 2024
1ae0b1f
return vector instead of unique_ptr
abe-winter Nov 18, 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
8 changes: 8 additions & 0 deletions src/viam/api/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ if (VIAMCPPSDK_USE_DYNAMIC_PROTOS)
${PROTO_GEN_DIR}/service/motion/v1/motion.grpc.pb.h
${PROTO_GEN_DIR}/service/motion/v1/motion.pb.cc
${PROTO_GEN_DIR}/service/motion/v1/motion.pb.h
${PROTO_GEN_DIR}/service/navigation/v1/navigation.grpc.pb.cc
${PROTO_GEN_DIR}/service/navigation/v1/navigation.grpc.pb.h
${PROTO_GEN_DIR}/service/navigation/v1/navigation.pb.cc
${PROTO_GEN_DIR}/service/navigation/v1/navigation.pb.h
${PROTO_GEN_DIR}/tagger/v1/tagger.grpc.pb.cc
${PROTO_GEN_DIR}/tagger/v1/tagger.grpc.pb.h
${PROTO_GEN_DIR}/tagger/v1/tagger.pb.cc
Expand Down Expand Up @@ -328,6 +332,8 @@ target_sources(viamapi
${PROTO_GEN_DIR}/service/mlmodel/v1/mlmodel.pb.cc
${PROTO_GEN_DIR}/service/motion/v1/motion.grpc.pb.cc
${PROTO_GEN_DIR}/service/motion/v1/motion.pb.cc
${PROTO_GEN_DIR}/service/navigation/v1/navigation.grpc.pb.cc
${PROTO_GEN_DIR}/service/navigation/v1/navigation.pb.cc
${PROTO_GEN_DIR}/tagger/v1/tagger.grpc.pb.cc
${PROTO_GEN_DIR}/tagger/v1/tagger.pb.cc
PUBLIC FILE_SET viamapi_includes TYPE HEADERS
Expand Down Expand Up @@ -385,6 +391,8 @@ target_sources(viamapi
${PROTO_GEN_DIR}/../../viam/api/service/mlmodel/v1/mlmodel.pb.h
${PROTO_GEN_DIR}/../../viam/api/service/motion/v1/motion.grpc.pb.h
${PROTO_GEN_DIR}/../../viam/api/service/motion/v1/motion.pb.h
${PROTO_GEN_DIR}/../../viam/api/service/navigation/v1/navigation.grpc.pb.h
${PROTO_GEN_DIR}/../../viam/api/service/navigation/v1/navigation.pb.h
${PROTO_GEN_DIR}/../../viam/api/tagger/v1/tagger.pb.h
)

Expand Down
4 changes: 4 additions & 0 deletions src/viam/sdk/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,16 @@ target_sources(viamsdk
services/generic.cpp
services/mlmodel.cpp
services/motion.cpp
services/navigation.cpp
services/private/generic_client.cpp
services/private/generic_server.cpp
services/private/mlmodel.cpp
services/private/mlmodel_client.cpp
services/private/mlmodel_server.cpp
services/private/motion_client.cpp
services/private/motion_server.cpp
services/private/navigation_client.cpp
services/private/navigation_server.cpp
services/service.cpp
spatialmath/geometry.cpp
spatialmath/orientation.cpp
Expand Down Expand Up @@ -179,6 +182,7 @@ target_sources(viamsdk
../../viam/sdk/services/generic.hpp
../../viam/sdk/services/mlmodel.hpp
../../viam/sdk/services/motion.hpp
../../viam/sdk/services/navigation.hpp
../../viam/sdk/services/service.hpp
../../viam/sdk/spatialmath/geometry.hpp
../../viam/sdk/spatialmath/orientation.hpp
Expand Down
61 changes: 61 additions & 0 deletions src/viam/sdk/common/proto_utils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/// @file common/proto_utils.hpp
///
/// @brief Utils that require generated proto includes. These should be #included
/// in cpp implementation files, but not in wrapper headers consumed by third party code.
#pragma once

#include <viam/api/common/v1/common.pb.h>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A semi-near-term goal for the C++ SDK is to move all the proto stuff out of public headers. Could you push this down into viam/sdk/common/private/proto_utils.hpp? That's how we indicate that files shouldn't be consumed except by files that form part of the SDK or published as part of the install step.


namespace viam {
namespace sdk {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add namespace impl here, so viam::sdk::impl. That's the namespace we use for any private things that shouldn't escape.

/// @brief Copies elements from a protobuf repeated pointer array into a std::vector. Src type
/// must be implicitly convertible to Dst (probably via operator on Src).
template <typename Src, typename Dst>
void vecToRepeatedPtr(const std::vector<Src>& vec, google::protobuf::RepeatedPtrField<Dst>& dest) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a slight preference for out parameters being taken by pointer, as it makes it clearer at the call site that the field is likely being mutated:

vecToRepeatedPtr(my_vec, dest);  // err, who is getting modified here?

vs

vecToRepeatedPtr(my_vec, &dest);  // ah, classic out parameter.

Others dislike this because they worry that it allows dest to be nullptr. I don't find that compelling because requiring it to be a reference doesn't prevent the opposite mistake:

RepeatedPtrField<X>* pdest = ...
vecToRepeatedPtr(my_vec, *pdest);  // oops, what if pdest is nullptr?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So generally speaking I'm very much against output parameters being passed as pointers, it's one of the things I dislike the most about google's C++ coding guidelines. I think with your counterexample above the point is that, in C++ and as high level as this code is, we generally aren't passing around pointer types in the first place, and the point of references is that they must point to a valid object or else it's UB. So as for

oops, what if pdest is nullptr

That's on the caller for dereferencing a null pointer in the first place, and is equally true of if my_vec was *p_my_vec for some reason, and this is kind of the point of C++ having reference types.

Callsite legibility I'm somewhat sympathetic to but would be better done with something like std::ref(arg) or gsl::output_parameter, because then you don't lose the non-null guarantee.

.....All that said, I think this could be a pointer parameter just for ABI insulation reasons

dest.Clear();
dest.Reserve(vec.size());
for (auto& x : vec) {
*dest.Add() = x.to_proto();
}
}

/// @brief Non-member to_proto() version. (necessary for moving generated types out of wrapper
/// headers). Template param F is a function that converts from Src to Dst.
template <typename Src, typename Dst>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More idiomatic would just to be take

template <typename Src, typename Callable>
void vecToRepeatedPtr(const std::vector<Src>& vec,
                      google::protobuf::RepeatedPtrField<Dst>& dest,
                      Callable&& c) {

Because then you can pass any sort of callable (std::function, lambda, function pointer as you have now).

You can then enforce the shape of the callable with a static assert or similar.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explain this one -- this is better because it would select this specialization and return a static assert error, rather than giving a long 'no matching template' error?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, as written, yours will only accept function pointers. I could be wrong, I'd need to test it out on godbolt.

void vecToRepeatedPtr(const std::vector<Src>& vec,
google::protobuf::RepeatedPtrField<Dst>& dest,
Dst to_proto(const Src&)) {
dest.Clear();
dest.Reserve(vec.size());
for (auto& x : vec) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would work with other containers than just std::vector right? std::array, std::list, etc.?

*dest.Add() = to_proto(x);
}
}

/// @brief Copies elements from a std::vector into a protobuf repeated pointer array. Src type
/// must be implicitly convertible to Dst (probably via constructor on Dst).
template <typename Src, typename Dst>
void repeatedPtrToVec(const google::protobuf::RepeatedPtrField<Src>& src, std::vector<Dst>& vec) {
vec.clear();
vec.reserve(src.size());
for (auto& x : src) {
vec.push_back(Dst::from_proto(x));
}
}

/// @brief Non-member to_proto() version. (necessary for moving generated types out of wrapper
/// headers). Template param F is a function that converts from Src to Dst.
template <typename Src, typename Dst>
void repeatedPtrToVec(const google::protobuf::RepeatedPtrField<Src>& src,
std::vector<Dst>& vec,
Dst from_proto(const Src&)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could eliminate the distinction between the converting and non-converting by just always taking a transformation function and defaulting it to std::identity (might need to get it from boost for now)

That actually has me wondering whether all of these are really glosses on std::transform and would be better implemented that way?

vec.clear();
vec.reserve(src.size());
for (auto& x : src) {
vec.push_back(from_proto(x));
}
}

} // namespace sdk
} // namespace viam
3 changes: 3 additions & 0 deletions src/viam/sdk/registry/registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
#include <viam/sdk/services/private/mlmodel_server.hpp>
#include <viam/sdk/services/private/motion_client.hpp>
#include <viam/sdk/services/private/motion_server.hpp>
#include <viam/sdk/services/private/navigation_client.hpp>
#include <viam/sdk/services/private/navigation_server.hpp>
#include <viam/sdk/services/service.hpp>

namespace viam {
Expand Down Expand Up @@ -190,6 +192,7 @@ void register_resources() {
Registry::register_resource<impl::GenericServiceClient, impl::GenericServiceServer>();
Registry::register_resource<impl::MLModelServiceClient, impl::MLModelServiceServer>();
Registry::register_resource<impl::MotionClient, impl::MotionServer>();
Registry::register_resource<impl::NavigationClient, impl::NavigationServer>();
}

void Registry::initialize() {
Expand Down
21 changes: 21 additions & 0 deletions src/viam/sdk/services/navigation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <viam/sdk/services/navigation.hpp>

#include <viam/api/service/navigation/v1/navigation.pb.h>
#include <viam/sdk/common/proto_utils.hpp>
#include <viam/sdk/common/utils.hpp>

namespace viam {
namespace sdk {

Navigation::Navigation(std::string name) : Service(std::move(name)){};

API Navigation::api() const {
return API::get<Navigation>();
}

API API::traits<Navigation>::api() {
return {kRDK, kService, "navigation"};
}

} // namespace sdk
} // namespace viam
102 changes: 102 additions & 0 deletions src/viam/sdk/services/navigation.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/// @file services/navigation.hpp
///
/// @brief Defines a `Navigation` service.
#pragma once

#include <string>

#include <viam/sdk/common/pose.hpp>
#include <viam/sdk/common/utils.hpp>
#include <viam/sdk/services/service.hpp>
#include <viam/sdk/spatialmath/geometry.hpp>

namespace viam {
namespace sdk {

class Navigation : public Service {
public:
enum class Mode : uint8_t {
k_unspecified,
k_manual,
k_waypoint,
k_explore,
};

enum class MapType : uint8_t {
k_unspecified,
k_none,
k_gps,
};

struct LocationResponse {
geo_point location;
double compass_heading;
};

struct Waypoint {
std::string id;
geo_point location;
};

struct Path {
std::string destination_waypoint_id;
std::vector<geo_point> geopoints;
};

API api() const override;

virtual Mode get_mode(const std::string name, const ProtoStruct& extra) = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is the public facing header, this is the one that should have doc comments. Also, please add blank lines between the end of the declaration of one method and the beginning of the next.

    virtual LocationResponse get_location(const std::string name, const ProtoStruct& extra) = 0;

    virtual std::unique_ptr<std::vector<Waypoint>> get_waypoints(const std::string name,
                                                                 const ProtoStruct& extra) = 0;

That, moreso, once comments are added:

    /// Some comment
    virtual LocationResponse get_location(const std::string name, const ProtoStruct& extra) = 0;

    /// Another comment
    virtual std::unique_ptr<std::vector<Waypoint>> get_waypoints(const std::string name,
                                                                 const ProtoStruct& extra) = 0;

virtual void set_mode(const std::string name, const Mode mode, const ProtoStruct& extra) = 0;
virtual LocationResponse get_location(const std::string name, const ProtoStruct& extra) = 0;
virtual std::unique_ptr<std::vector<Waypoint>> get_waypoints(const std::string name,
const ProtoStruct& extra) = 0;
virtual void add_waypoint(const std::string name,
const geo_point& location,
const ProtoStruct& extra) = 0;
virtual void remove_waypoint(const std::string name,
const std::string id,
const ProtoStruct& extra) = 0;
virtual std::unique_ptr<std::vector<geo_geometry>> get_obstacles(const std::string name,
const ProtoStruct& extra) = 0;
virtual std::unique_ptr<std::vector<Path>> get_paths(const std::string name,
const ProtoStruct& extra) = 0;
virtual MapType get_properties(const std::string) = 0;
virtual ProtoStruct do_command(const ProtoStruct& command) = 0;

// overloads without `extra` param.
inline Mode get_mode(const std::string name) {
return get_mode(name, {});
}
inline void set_mode(const std::string name, const Mode mode) {
set_mode(name, mode, {});
}
inline LocationResponse get_location(const std::string name) {
return get_location(name, {});
}
inline std::unique_ptr<std::vector<Waypoint>> get_waypoints(const std::string name) {
return get_waypoints(name, {});
}
inline void add_waypoint(const std::string name, const geo_point& location) {
add_waypoint(name, location, {});
}
inline void remove_waypoint(const std::string name, const std::string id) {
remove_waypoint(name, id, {});
}
inline std::unique_ptr<std::vector<geo_geometry>> get_obstacles(const std::string name) {
return get_obstacles(name, {});
}
inline std::unique_ptr<std::vector<Path>> get_paths(const std::string name) {
return get_paths(name, {});
}

protected:
explicit Navigation(std::string name);
};

template <>
struct API::traits<Navigation> {
static API api();
};

} // namespace sdk
} // namespace viam
Loading