C++ Client Library¶
moteus provides a C++ library that can be used to command and control moteus controllers using a supported CAN-FD adapter.
Integration¶
The moteus C++ library is header only, so there are several possible options for integrating the C++ library into your project.
Copy the source files: One option is to copy all the relevant headers into your source tree:
CMake: There exists a top level CMakeLists.txt file that can be used with CMake's FetchContent to incorporate the headers into your project.
include(FetchContent)
FetchContent_Declare(
moteus
GIT_REPOSITORY https://github.com/mjbots/moteus.git
# Pin to a specific commit for a reproducible build. The trailing
# comment names the corresponding C++ release tag for readers.
GIT_TAG a1b2c3d4e5f6789012345678901234567890abcd # cpp/v1.0.0
)
FetchContent_MakeAvailable(moteus)
add_executable(myproject myproject.cc)
target_link_libraries(myproject moteus::cpp)
Pin to the commit hash rather than the tag itself. Tags are mutable
in principle (they can be force-pushed or recreated), so a hash is the
only reference that guarantees a reproducible fetch. The
# cpp/vX.Y.Z trailing comment keeps the version human-readable and
is what you update — together with the hash — when bumping to a new
release.
The latest C++ release and its commit hash are listed on the
Releases page — filter
the page by typing cpp/ to see only C++ releases.
bazel: moteus does export bazel BUILD files and can be integrated into bazel projects using that mechanism as well.
Usage¶
Basic usage is similar, although slightly different to the python library. A minimal example follows:
#include <iostream>
#include <unistd.h>
#include "moteus.h"
namespace moteus = mjbots::moteus;
int main(int argc, char** argv) {
moteus::Controller::DefaultArgProcess(argc, argv);
moteus::Controller c([]() {
moteus::Controller::Options options;
options.id = 1;
return options;
}());
moteus::PositionMode::Command command;
command.position = std::numeric_limits<double>::quiet_NaN();
while (true) {
const auto maybe_result = c.SetPosition(command);
if (maybe_result) {
const auto& v = maybe_result->values;
std::cout << "Mode: " << v.mode
<< " Fault: " << v.fault
<< "Position: " << v.position
<< " Velocity: " << v.velocity
<< "\n";
}
::usleep(10000);
}
return 0;
}
Specifying alternate query registers¶
By default, only a subset of registers are queried by the library.
Common register selection¶
To select other common options you can either (a) change the default query resolution or (b) pass an "override" query resolution.
Option (a): Change the default¶
moteus::Controller c([]() {
moteus::Controller::Options options;
options.query_format.power = moteus::kFloat;
return options;
}());
Option (b): Specify an "override"¶
moteus::Controller c;
moteus::PositionMode::Command command;
moteus::Query::Formay query_override;
query_override.power = moteus::kFloat;
c.SetPosition(command, nullptr, &query_override);
Less common register selection¶
For registers which do not have predefined fields in Query::Format, you can use the extra mechanism through either the constructor options or override argument.
moteus::Controller c([]() {
moteus::Controller::Options options;
options.query_format.extra[0].register_number = moteus::Register::kAux1AnalogIn1;
options.query_format.extra[0].resolution = moteus::kFloat;
return options;
}());
Specifying alternate command registers¶
As with queries, by default, only a subset of registers are sent with SetPosition or MakePosition commands. Without additional work, only "position" and "velocity" are sent. To select others, they can either be changed through (a) the defaults or by (b) overriding them.
Option (a): Change the default¶
moteus::Controller c([]() {
moteus::Controller::Options options;
options.position_format.feedforward_torque = moteus::kFloat;
return options;
}());
moteus::PositionMode::Command command;
command.position = std::numeric_limits<double>::quiet_NaN();
command.velocity = 0.0;
command.feedforward_torque = 0.1;
c.SetPosition(command);
Option (b): Specify an "override"¶
moteus::Controller c;
moteus::PositionMode::Command command;
command.position = std::numeric_limits<double>::quiet_NaN();
command.velocity = 0.0;
command.feedforward_torque = 0.1;
moteus::PositionMode::Format format;
format.feedforward_torque = moteus::kFloat;
c.SetPosition(command, &format);
Alternate Usage Modes¶
Like the python library, the C++ library has two modes of operation. One designed for ease of use, and the other for maximizing bus utilization and command rate. The former are the Set* variant methods used above. Like python, there exist Make* variant methods which generate a frame, but do not send it. Those can be used with a manually constructed transport.
auto transport = moteus::MakeSingletonTransport();
moteus::Controller c([&]() {
moteus::Controller::Options options;
options.transport = transport;
return options;
}());
std::vector<moteus::CanFdFrame> commands_to_send;
std::vector<moteus::CanFdFrame> replies_to_receive;
moteus::PositionMode::Command command;
commands_to_send.push_back(c.MakePosition(command));
transport->BlockingCycle(
commands_to_send.data(),
commands_to_send.size(),
&replies_to_receive);