Skip to content

Commit

Permalink
✨ Add rmd_drc_v2 and rmd_mc_x_v2 drivers (#20)
Browse files Browse the repository at this point in the history
* ✨ Add rmd_drc_v2 and rmd_mc_x_v2 drivers

These drivers use the v2 can interfaces, primarily
`hal::can_transceiver`.

* 🐛 Add can filter to drivers

* ⬆️ libhal/5.4.1

* Remove demos updates, move to new branch
  • Loading branch information
kammce authored Jan 4, 2025
1 parent 61377f8 commit 0911b6d
Show file tree
Hide file tree
Showing 15 changed files with 2,414 additions and 24 deletions.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@ libhal_test_and_make_library(
src/rc_servo.cpp
src/smart_servo/rmd/drc_adaptors.cpp
src/smart_servo/rmd/drc.cpp
src/smart_servo/rmd/drc_v2.cpp
src/smart_servo/rmd/mc_x_adaptors.cpp
src/smart_servo/rmd/mc_x.cpp
src/smart_servo/rmd/mc_x_v2.cpp

TEST_SOURCES
tests/main.test.cpp
tests/rc_servo.test.cpp
tests/smart_servo/rmd/drc.test.cpp
# tests/smart_servo/rmd/drc_v2.test.cpp
tests/smart_servo/rmd/mc_x.test.cpp
tests/smart_servo/rmd/drc_adaptors.test.cpp

Expand Down
8 changes: 3 additions & 5 deletions conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,12 @@ class libhal_actuator_conan(ConanFile):
topics = ("actuator", "libhal", "driver")
settings = "compiler", "build_type", "os", "arch"

python_requires = "libhal-bootstrap/[^3.0.0]"
python_requires = "libhal-bootstrap/[^4.1.1]"
python_requires_extend = "libhal-bootstrap.library"

def requirements(self):
# Adds libhal and libhal-util as transitive headers, meaning library
# consumers get the libhal and libhal-util headers downstream.
bootstrap = self.python_requires["libhal-bootstrap"]
bootstrap.module.add_library_requirements(self)
self.requires("libhal/[^4.9.0]", transitive_headers=True)
self.requires("libhal-util/[^5.4.1]", transitive_headers=True)
self.requires("libhal-canrouter/[^3.0.0]")

def package_info(self):
Expand Down
157 changes: 157 additions & 0 deletions demos/applications/drc_v2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// Copyright 2024 Khalil Estell
//
// 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.

#include <libhal-actuator/smart_servo/rmd/drc_v2.hpp>
#include <libhal-util/can.hpp>
#include <libhal-util/serial.hpp>
#include <libhal-util/steady_clock.hpp>

#include <resource_list.hpp>

void application(resource_list& p_resources)
{
using namespace std::chrono_literals;
using namespace hal::literals;

auto& clock = *p_resources.clock.value();
auto& console = *p_resources.console.value();
auto& can_transceiver = *p_resources.can_transceiver.value();
auto& can_bus_manager = *p_resources.can_bus_manager.value();
auto& can_identifier_filter = *p_resources.can_identifier_filter.value();

// Needs to be set to this baud rate to work with the default firmware CAN
// baud rate.
can_bus_manager.baud_rate(1.0_MHz);

hal::print(console, "RMD DRC Smart Servo Application Starting...\n\n");

constexpr std::uint16_t starting_device_address = 0x140;
std::uint16_t address_offset = 0;

while (true) {
try {
auto const address = starting_device_address + address_offset;
hal::actuator::rmd_drc_v2 drc(
can_transceiver, can_identifier_filter, clock, 6.0f, address);

auto print_feedback = [&drc, &console]() {
drc.feedback_request(hal::actuator::rmd_drc_v2::read::status_2);
drc.feedback_request(
hal::actuator::rmd_drc_v2::read::multi_turns_angle);
drc.feedback_request(
hal::actuator::rmd_drc_v2::read::status_1_and_error_flags);

hal::print<2048>(
console,
"[%u] =================================\n"
"raw_multi_turn_angle = %f\n"
"raw_current = %d\n"
"raw_speed = %d\n"
"raw_volts = %d\n"
"encoder = %d\n"
"raw_motor_temperature = %d"
"\n"
"over_voltage_protection_tripped = %d\n"
"over_temperature_protection_tripped = %d\n"
"-------\n"
"angle() = %f °deg\n"
"current() = %f A\n"
"speed() = %f rpm\n"
"volts() = %f V\n"
"temperature() = %f °C\n\n",

drc.feedback().message_number,
static_cast<float>(drc.feedback().raw_multi_turn_angle),
drc.feedback().raw_current,
drc.feedback().raw_speed,
drc.feedback().raw_volts,
drc.feedback().encoder,
drc.feedback().raw_motor_temperature,
drc.feedback().over_voltage_protection_tripped(),
drc.feedback().over_temperature_protection_tripped(),
drc.feedback().angle(),
drc.feedback().current(),
drc.feedback().speed(),
drc.feedback().volts(),
drc.feedback().temperature());
};

hal::delay(clock, 500ms);

while (true) {
drc.velocity_control(10.0_rpm);
hal::delay(clock, 5000ms);
print_feedback();

drc.velocity_control(-10.0_rpm);
hal::delay(clock, 5000ms);
print_feedback();

drc.position_control(0.0_deg, 50.0_rpm);
hal::delay(clock, 5000ms);
print_feedback();

drc.position_control(-45.0_deg, 50.0_rpm);
hal::delay(clock, 5000ms);
print_feedback();

drc.position_control(90.0_deg, 50.0_rpm);
hal::delay(clock, 5000ms);
print_feedback();

drc.position_control(180.0_deg, 50.0_rpm);
hal::delay(clock, 5000ms);
print_feedback();

drc.position_control(-360.0_deg, 50.0_rpm);
hal::delay(clock, 5000ms);
print_feedback();

drc.position_control(0.0_deg, 50.0_rpm);
hal::delay(clock, 5000ms);
print_feedback();
}
} catch (hal::timed_out const&) {
hal::print(
console,
"hal::timed_out exception! which means that the device did not "
"respond. Moving to the next device address in the list.\n");
} catch (hal::resource_unavailable_try_again const& p_error) {
hal::print(console, "hal::resource_unavailable_try_again\n");
if (p_error.instance() == &can_transceiver) {
hal::print(
console,
"\n"
"The CAN peripheral has received no acknowledgements from any other "
"device on the bus. It appears as if the peripheral is not connected "
"to a can network. This can happen if the baud rate is incorrect, "
"the CAN transceiver is not functioning, or the devices on the bus "
"are not responding."
"\n"
"Calling terminate!"
"\n"
"Consider powering down the system and checking all of your "
"connections before restarting the application.");
std::terminate();
}
// otherwise keep trying with other addresses
} catch (...) {
hal::print(console, "Unknown exception caught in (...) block\n");
throw; // see if anyone else can handle the exception
}

address_offset = (address_offset + 1) % 8;
hal::delay(clock, 1s);
}
}
131 changes: 131 additions & 0 deletions demos/applications/drc_v2_resources.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright 2024 Khalil Estell
//
// 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.

#include <libhal-actuator/smart_servo/rmd/drc_v2.hpp>
#include <libhal-util/can.hpp>
#include <libhal-util/serial.hpp>
#include <libhal-util/steady_clock.hpp>

#include <resource_list.hpp>

void application(resource_list& p_resources)
{
using namespace std::chrono_literals;
using namespace hal::literals;

auto& clock = *p_resources.clock.value();
auto& console = *p_resources.console.value();
auto& can_transceiver = *p_resources.can_transceiver.value();
auto& can_bus_manager = *p_resources.can_bus_manager.value();
auto& can_identifier_filter = *p_resources.can_identifier_filter.value();

// Needs to be set to this baud rate to work with the default firmware CAN
// baud rate.
can_bus_manager.baud_rate(1.0_MHz);

hal::print(console, "RMD DRC Smart Servo Application Starting...\n\n");

constexpr std::uint16_t starting_device_address = 0x140;
std::uint16_t address_offset = 0;

while (true) {
try {
auto const address = starting_device_address + address_offset;
hal::actuator::rmd_drc_v2 drc(
can_transceiver, can_identifier_filter, clock, 6.0f, address);

auto motor = drc.acquire_motor(20.0_rpm);
auto servo = drc.acquire_servo(20.0_rpm);
auto temperature_sensor = drc.acquire_temperature_sensor();
auto rotation_sensor = drc.acquire_rotation_sensor();

auto print_feedback =
[&console, &temperature_sensor, &rotation_sensor]() {
hal::print<2048>(console,
"[%u] =================================\n"
"shaft angle = %f deg\n"
"temperature = %f C\n"
"\n\n",
temperature_sensor.read(),
rotation_sensor.read());
};

hal::delay(clock, 500ms);

while (true) {
motor.power(0.5f);
hal::delay(clock, 5000ms);
print_feedback();

motor.power(-0.5f);
hal::delay(clock, 5000ms);
print_feedback();

servo.position(0.0_deg);
hal::delay(clock, 5000ms);
print_feedback();

servo.position(-45.0_deg);
hal::delay(clock, 5000ms);
print_feedback();

servo.position(90.0_deg);
hal::delay(clock, 5000ms);
print_feedback();

servo.position(180.0_deg);
hal::delay(clock, 5000ms);
print_feedback();

servo.position(-360.0_deg);
hal::delay(clock, 5000ms);
print_feedback();

servo.position(0.0_deg);
hal::delay(clock, 5000ms);
print_feedback();
}
} catch (hal::timed_out const&) {
hal::print(
console,
"hal::timed_out exception! which means that the device did not "
"respond. Moving to the next device address in the list.\n");
} catch (hal::resource_unavailable_try_again const& p_error) {
hal::print(console, "hal::resource_unavailable_try_again\n");
if (p_error.instance() == &can_transceiver) {
hal::print(
console,
"\n"
"The CAN peripheral has received no acknowledgements from any other "
"device on the bus. It appears as if the peripheral is not connected "
"to a can network. This can happen if the baud rate is incorrect, "
"the CAN transceiver is not functioning, or the devices on the bus "
"are not responding."
"\n"
"Calling terminate!"
"\n"
"Consider powering down the system and checking all of your "
"connections before restarting the application.");
std::terminate();
}
// otherwise keep trying with other addresses
} catch (...) {
hal::print(console, "Unknown exception caught in (...) block\n");
throw; // see if anyone else can handle the exception
}

address_offset = (address_offset + 1) % 8;
hal::delay(clock, 1s);
}
}
Loading

0 comments on commit 0911b6d

Please sign in to comment.