Skip to content

Commit 282d2c4

Browse files
committed
Split MotorDriver into Mcu interface and SerialMcu
Signed-off-by: Javier Balloffet <javier.balloffet@gmail.com>
1 parent 3da85f7 commit 282d2c4

9 files changed

Lines changed: 216 additions & 98 deletions

File tree

andino_base/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ The hardware-software-ros interaction in the `andino` project is developed using
77
This package:
88
- Implements `andino`'s [hardware interface](https://control.ros.org/master/doc/ros2_control/hardware_interface/doc/writing_new_hardware_interface.html).
99
- Provides a communication with microcontroller:
10-
- `andino_base::MotorDriver` class is in charge of the Serial communication for commanding the motors.
11-
- An application is provided for evaluating the communication: Check `applications/motor_driver_demo.cpp`. To use this application simply execute `motor_driver_demo --help` to see the options.
10+
- `andino_base::SerialMcu` class (implementing the `andino_base::Mcu` interface) is in charge of the Serial communication with `andino_firmware`, exposing its full command set (motors, encoders, PID tuning, GPIOs and IMU).
11+
- An application is provided for evaluating the communication: Check `applications/serial_mcu_demo.cpp`. To use this application simply execute `serial_mcu_demo --help` to see the options.
1212
- This communication module is used by the hardware interface implementation.
1313

1414
## Hardware Interface
@@ -40,12 +40,12 @@ This hardware interface uses the following command interfaces per joint (for lef
4040
- *Velocity*: The velocity received (rad/s) is traduced to microcontroller's velocity nomenclature for the motors.
4141

4242

43-
## Motor Driver Application
43+
## Serial MCU Application
4444

4545
An application for testing the connection with the microcontroller is provided.
46-
After installing this package the application called `motor_driver_demo` can be used.
46+
After installing this package the application called `serial_mcu_demo` can be used.
4747
```
48-
motor_driver_demo --help
48+
serial_mcu_demo --help
4949
```
5050

5151
This application allows verifying the communication with the microcontroller for controlling the motors. Commands for reading the encoders or individually setting a velocity for the motors is some of the possibilities.

andino_base/applications/CMakeLists.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
add_executable(motor_driver_demo motor_driver_demo.cpp)
1+
add_executable(serial_mcu_demo serial_mcu_demo.cpp)
22

3-
target_include_directories(motor_driver_demo
3+
target_include_directories(serial_mcu_demo
44
PUBLIC
55
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
66
$<INSTALL_INTERFACE:include>)
77

8-
target_link_libraries(motor_driver_demo
8+
target_link_libraries(serial_mcu_demo
99
PUBLIC
1010
gflags
11-
motor_driver
11+
serial_mcu
1212
)
1313

1414
install(
1515
TARGETS
16-
motor_driver_demo
16+
serial_mcu_demo
1717
EXPORT ${PROJECT_NAME}-targets
1818
ARCHIVE DESTINATION lib
1919
LIBRARY DESTINATION lib

andino_base/applications/motor_driver_demo.cpp renamed to andino_base/applications/serial_mcu_demo.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,39 +32,40 @@
3232

3333
#include <gflags/gflags.h>
3434

35-
#include "andino_base/motor_driver.h"
35+
#include "andino_base/serial_mcu.h"
3636

3737
DEFINE_string(serial_port, "/dev/ttyUSB0", "Serial port");
3838
DEFINE_int32(baud_rate, 57600, "Baud rate");
3939
DEFINE_int32(timeout_ms, 1000, "Timeout in milliseconds for receiving a response from the Microcontroller");
4040

41-
DEFINE_string(msg, "e", "Motor driver message(default read encoders)");
41+
DEFINE_string(msg, "e", "MCU message(default read encoders)");
4242

4343
namespace andino_base {
4444
namespace applications {
4545

4646
// Returns a string with the usage message.
4747
std::string GetUsageMessage() {
4848
std::stringstream ss;
49-
ss << "CLI for easy test of the MotorDriver class" << std::endl << std::endl;
50-
ss << " motor_driver_demo --serial_port=/dev/ttyUSB0 --msg='e' " << std::endl << std::endl;
51-
ss << " motor_driver_demo --msg='o 255 255' " << std::endl << std::endl;
49+
ss << "CLI for easy test of the SerialMcu class" << std::endl << std::endl;
50+
ss << " serial_mcu_demo --serial_port=/dev/ttyUSB0 --msg='e' " << std::endl << std::endl;
51+
ss << " serial_mcu_demo --msg='o 255 255' " << std::endl << std::endl;
5252
return ss.str();
5353
}
5454

5555
int Main(int argc, char* argv[]) {
5656
gflags::SetUsageMessage(GetUsageMessage());
5757
gflags::ParseCommandLineFlags(&argc, &argv, true);
5858

59-
MotorDriver motor_driver;
60-
motor_driver.Setup(FLAGS_serial_port, FLAGS_baud_rate, FLAGS_timeout_ms);
59+
SerialMcu serial_mcu;
60+
serial_mcu.setup(FLAGS_serial_port, FLAGS_baud_rate, FLAGS_timeout_ms);
6161

62-
std::cout << "Motor driver is connected: " << (motor_driver.is_connected() ? "True" : "False") << std::endl;
62+
std::cout << "MCU is connected: " << (serial_mcu.is_connected() ? "True" : "False") << std::endl;
6363

6464
// Send message
65-
std::cout << "Sending message: " << FLAGS_msg << std::endl;
66-
const std::string response = motor_driver.SendMsg(FLAGS_msg);
67-
std::cout << "Response: " << response << std::endl;
65+
// TODO(jballoffet): Change to use public API.
66+
// std::cout << "Sending message: " << FLAGS_msg << std::endl;
67+
// const std::string response = serial_mcu.SendMsg(FLAGS_msg);
68+
// std::cout << "Response: " << response << std::endl;
6869
return 0;
6970
}
7071

andino_base/include/andino_base/diffdrive_andino.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
#include <rclcpp_lifecycle/node_interfaces/lifecycle_node_interface.hpp>
4141
#include <rclcpp_lifecycle/state.hpp>
4242

43-
#include "andino_base/motor_driver.h"
43+
#include "andino_base/serial_mcu.h"
4444
#include "andino_base/wheel.h"
4545

4646
namespace andino_base {
@@ -92,8 +92,8 @@ class DiffDriveAndino : public hardware_interface::SystemInterface {
9292

9393
// Configuration parameters.
9494
Config config_;
95-
// Communication with the firmware in charge of controlling the motors.
96-
MotorDriver motor_driver_;
95+
// Communication with the microcontroller running andino_firmware.
96+
SerialMcu serial_mcu_;
9797
// Left wheel of the robot.
9898
Wheel left_wheel_;
9999
// Right wheel of the robot.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// BSD 3-Clause License
2+
//
3+
// Copyright (c) 2026, Ekumen Inc.
4+
// All rights reserved.
5+
//
6+
// Redistribution and use in source and binary forms, with or without
7+
// modification, are permitted provided that the following conditions are met:
8+
//
9+
// 1. Redistributions of source code must retain the above copyright notice, this
10+
// list of conditions and the following disclaimer.
11+
//
12+
// 2. Redistributions in binary form must reproduce the above copyright notice,
13+
// this list of conditions and the following disclaimer in the documentation
14+
// and/or other materials provided with the distribution.
15+
//
16+
// 3. Neither the name of the copyright holder nor the names of its
17+
// contributors may be used to endorse or promote products derived from
18+
// this software without specific prior written permission.
19+
//
20+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24+
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26+
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27+
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28+
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
#pragma once
31+
32+
#include <array>
33+
34+
namespace andino_base {
35+
36+
/// \brief Interface to the microcontroller running andino_firmware.
37+
/// It exposes the full set of commands supported by andino_firmware.
38+
class Mcu {
39+
public:
40+
/// @brief Holds encoder sensors reading. First value is the left encoder, second is the right one.
41+
using EncodersData = std::array<int, 2>;
42+
43+
/// @brief Holds IMU sensor reading.
44+
struct ImuData {
45+
/// @brief Absolute orientation as a quaternion, in (x, y, z, w) order.
46+
std::array<double, 4> orientation{};
47+
/// @brief Angular velocity [rad/s], in (x, y, z) order.
48+
std::array<double, 3> angular_velocity{};
49+
/// @brief Linear acceleration [m/s^2], in (x, y, z) order.
50+
std::array<double, 3> linear_acceleration{};
51+
};
52+
53+
/// @brief Holds encoders and IMU sensors reading.
54+
struct EncodersAndImuData {
55+
/// @brief The encoder values.
56+
EncodersData encoders_data{};
57+
/// @brief The IMU sensor reading.
58+
ImuData imu_data{};
59+
};
60+
61+
virtual ~Mcu() = default;
62+
63+
/// @brief Checks if the microcontroller is connected.
64+
/// @return True if the microcontroller is connected, false otherwise.
65+
virtual bool is_connected() const = 0;
66+
67+
/// @brief Resets the encoder sensors.
68+
virtual void reset_encoders() = 0;
69+
70+
/// @brief Returns the encoder sensors data.
71+
/// @returns The encoder sensors data.
72+
virtual EncodersData read_encoders() = 0;
73+
74+
/// @brief Checks if there is an IMU sensor available.
75+
/// @returns True if there is an IMU sensor available, false otherwise.
76+
virtual bool is_imu_available() = 0;
77+
78+
/// @brief Returns the encoder sensors and IMU sensor data.
79+
/// @returns The encoder sensors and IMU sensor data.
80+
virtual EncodersAndImuData read_encoders_and_imu() = 0;
81+
82+
/// @brief Sets the motors speed [ticks/s].
83+
/// @param left_motor_speed Speed value for the left motor.
84+
/// @param right_motor_speed Speed value for the right motor.
85+
virtual void set_motors_speed(int left_motor_speed, int right_motor_speed) = 0;
86+
87+
/// @brief Sets the motors PWM [duty range: 0-255].
88+
/// @param left_motor_pwm PWM value for the left motor.
89+
/// @param right_motor_pwm PWM value for the right motor.
90+
virtual void set_motors_pwm(int left_motor_pwm, int right_motor_pwm) = 0;
91+
92+
/// @brief Sets the PID tuning gains.
93+
/// @param kp Proportional gain.
94+
/// @param kd Derivative gain.
95+
/// @param ki Integral gain.
96+
/// @param ko Offset gain.
97+
virtual void set_pid_tuning_gains(float kp, float kd, float ki, float ko) = 0;
98+
};
99+
100+
} // namespace andino_base

andino_base/include/andino_base/motor_driver.h renamed to andino_base/include/andino_base/serial_mcu.h

Lines changed: 37 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -29,65 +29,56 @@
2929
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3030
#pragma once
3131

32-
#include <array>
33-
#include <cstdint>
32+
#include <string>
3433

3534
#include <libserial/SerialPort.h>
3635

36+
#include "andino_base/mcu.h"
37+
3738
namespace andino_base {
3839

39-
/// \brief Class to handle serial communication with the motor driver
40-
/// It is used to send commands to the motor driver and read encoder values.
41-
/// The use:
42-
/// 1. Create an instance of the class.
43-
/// 2. Call Setup() to initialize the serial connection.
44-
/// 3. Use api to send commands to the motor driver.
45-
class MotorDriver {
40+
/// \brief This class provides a serial implementation of the MCU interface.
41+
class SerialMcu : public Mcu {
4642
public:
47-
/// @brief Type to store the encoder values.
48-
using Encoders = std::array<int, 2>;
49-
5043
/// @brief Default constructor.
51-
MotorDriver() = default;
44+
SerialMcu() = default;
5245

46+
/// @brief Configures the serial communication.
5347
/// @param[in] serial_device Path to the serial device(eg. /dev/ttyACM0)
5448
/// @param[in] baud_rate Baud rate of the serial connection(eg. 57600)
5549
/// @param[in] timeout_ms Timeout in milliseconds.
56-
void Setup(const std::string& serial_device, int32_t baud_rate, int32_t timeout_ms);
57-
58-
/// @brief Send an empty message to the motor driver. The use of this function is to
59-
/// ensure that the motor driver is ready to receive a new command.
60-
void SendEmptyMsg();
61-
62-
/// @brief Read the encoder values from the motor driver.
63-
/// First value is the left encoder, second value is the right encoder.
64-
/// @returns The encoder values.
65-
Encoders ReadEncoderValues();
66-
67-
/// @brief Set the motor values.
68-
/// The unit of the values is in encoder ticks per revolution.
69-
/// @param val_1 Value for the first motor.
70-
/// @param val_2 Value for the second motor.
71-
void SetMotorValues(int val_1, int val_2);
72-
73-
/// @brief Set the PID values.
74-
/// @param k_p Proportional gain.
75-
/// @param k_d Derivative gain.
76-
/// @param k_i Integral gain.
77-
/// @param k_o Offset gain.
78-
void SetPidValues(float k_p, float k_d, float k_i, float k_o);
79-
80-
/// @brief Check if the serial connection is open.
81-
/// @return True if the serial connection is open, false otherwise.
82-
bool is_connected() const;
83-
84-
/// @brief Send a message to the motor driver and read the response.
85-
/// The message is sent with a carriage return appended to it.
86-
/// @param[in] msg_to_send Message to send to the motor driver.
87-
/// @returns The response from the motor driver.
88-
std::string SendMsg(const std::string& msg_to_send);
50+
void setup(const std::string& serial_device, int32_t baud_rate, int32_t timeout_ms);
51+
52+
/// @brief Implements Mcu interface class API.
53+
bool is_connected() const override;
54+
55+
/// @brief Implements Mcu interface class API.
56+
void reset_encoders() override;
57+
58+
/// @brief Implements Mcu interface class API.
59+
EncodersData read_encoders() override;
60+
61+
/// @brief Implements Mcu interface class API.
62+
bool is_imu_available() override;
63+
64+
/// @brief Implements Mcu interface class API.
65+
EncodersAndImuData read_encoders_and_imu() override;
66+
67+
/// @brief Implements Mcu interface class API.
68+
void set_motors_speed(int left_motor_speed, int right_motor_speed) override;
69+
70+
/// @brief Implements Mcu interface class API.
71+
void set_motors_pwm(int left_motor_pwm, int right_motor_pwm) override;
72+
73+
/// @brief Implements Mcu interface class API.
74+
void set_pid_tuning_gains(float kp, float kd, float ki, float ko) override;
8975

9076
private:
77+
/// @brief Sends a message to the microcontroller and reads the response.
78+
/// @param msg Message to send to the microcontroller.
79+
/// @returns The response from the microcontroller.
80+
std::string send_message(const std::string& msg);
81+
9182
// Underlying serial connection.
9283
LibSerial::SerialPort serial_port_;
9384

andino_base/src/CMakeLists.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
add_library(motor_driver SHARED motor_driver.cpp)
1+
add_library(serial_mcu SHARED serial_mcu.cpp)
22

3-
target_include_directories(motor_driver
3+
target_include_directories(serial_mcu
44
PUBLIC
55
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
66
$<INSTALL_INTERFACE:include>)
77

88
# Reference: See libserial example project for integration with CMake
9-
target_include_directories(motor_driver PUBLIC ${SERIAL_INCLUDE_DIRS})
10-
target_link_libraries(motor_driver PUBLIC ${SERIAL_LDFLAGS} ${CMAKE_THREAD_LIBS_INIT})
9+
target_include_directories(serial_mcu PUBLIC ${SERIAL_INCLUDE_DIRS})
10+
target_link_libraries(serial_mcu PUBLIC ${SERIAL_LDFLAGS} ${CMAKE_THREAD_LIBS_INIT})
1111

1212

1313
add_library(diffdrive_andino SHARED diffdrive_andino.cpp wheel.cpp)
@@ -24,10 +24,10 @@ ament_target_dependencies(diffdrive_andino
2424
rclcpp
2525
)
2626

27-
target_link_libraries(diffdrive_andino PUBLIC motor_driver)
27+
target_link_libraries(diffdrive_andino PUBLIC serial_mcu)
2828

2929
install(
30-
TARGETS diffdrive_andino motor_driver
30+
TARGETS diffdrive_andino serial_mcu
3131
EXPORT ${PROJECT_NAME}-targets
3232
ARCHIVE DESTINATION lib
3333
LIBRARY DESTINATION lib

0 commit comments

Comments
 (0)