From e366d50cf94eeb13a3c84ec4630a4da733668d48 Mon Sep 17 00:00:00 2001 From: Brian Lerner Date: Sat, 3 May 2025 14:12:34 -0400 Subject: [PATCH 1/6] adds script and adds changes to enable multiple version of ubuntu to work --- CMakeLists.txt | 48 ++++++++++++++++++++++++++-- install_myactuator_rmd.sh | 66 +++++++++++++++++++++++++++++++++++++++ setup.py | 3 +- src/can/node.cpp | 7 ++++- src/can/utilities.cpp | 21 ++++++++++++- 5 files changed, 140 insertions(+), 5 deletions(-) create mode 100755 install_myactuator_rmd.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 477df40..4d441d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,9 @@ cmake_minimum_required(VERSION 3.20) project(myactuator_rmd VERSION 0.0.1) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + option(PYTHON_BINDINGS "Building Python bindings" OFF) option(BUILD_TESTING "Build unit and integration tests" OFF) option(SETUP_TEST_IFNAME "Set-up the test VCAN interface automatically" OFF) @@ -39,7 +42,27 @@ target_include_directories(myactuator_rmd PUBLIC $ ) set(MYACTUATOR_RMD_LIBRARIES "") -target_link_libraries(myactuator_rmd PUBLIC + +# --- Check for CAN frame member name --- +include(CheckCXXSourceCompiles) +check_cxx_source_compiles(" +#include +int main() { + struct can_frame frame; + frame.can_dlc = 0; + return 0; +}" HAVE_CAN_DLC) + +if(HAVE_CAN_DLC) + message(STATUS "Detected can_frame.can_dlc member.") + target_compile_definitions(myactuator_rmd PUBLIC HAVE_CAN_DLC) +else() + message(STATUS "Using can_frame.len member.") + # Assuming 'len' is the alternative, no specific define needed unless code requires it +endif() +# -------------------------------------- + +target_link_libraries(myactuator_rmd PUBLIC ${MYACTUATOR_RMD_LIBRARIES} ) install(DIRECTORY include/ @@ -57,7 +80,24 @@ if(PYTHON_BINDINGS) Development Interpreter ) - find_package(pybind11 CONFIG REQUIRED) + + # --- Dynamically find pybind11 CMake directory --- + execute_process( + COMMAND "${Python3_EXECUTABLE}" -m pybind11 --cmakedir + OUTPUT_VARIABLE PYBIND11_CMAKE_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE PYBIND11_RESULT + ERROR_QUIET + ) + if(PYBIND11_RESULT EQUAL 0 AND IS_DIRECTORY "${PYBIND11_CMAKE_DIR}") + set(pybind11_DIR "${PYBIND11_CMAKE_DIR}") + message(STATUS "Found pybind11 CMake dir via Python: ${pybind11_DIR}") + else() + message(WARNING "Could not find pybind11 CMake dir via 'python3 -m pybind11 --cmakedir'. Falling back to standard find_package.") + endif() + # ------------------------------------------------- + + find_package(pybind11 REQUIRED) pybind11_add_module(myactuator_rmd_py bindings/myactuator_rmd.cpp @@ -65,6 +105,10 @@ if(PYTHON_BINDINGS) target_compile_features(myactuator_rmd_py PUBLIC cxx_std_17 ) + # Add HAVE_CAN_DLC definition if needed by bindings (unlikely, but for completeness) + if(HAVE_CAN_DLC) + target_compile_definitions(myactuator_rmd_py PUBLIC HAVE_CAN_DLC) + endif() target_link_libraries(myactuator_rmd_py PUBLIC myactuator_rmd ) diff --git a/install_myactuator_rmd.sh b/install_myactuator_rmd.sh new file mode 100755 index 0000000..a7e93cc --- /dev/null +++ b/install_myactuator_rmd.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +# install_myactuator_rmd.sh +# Installs the myactuator_rmd_py package from the current directory. +# Assumes prerequisites like Python 3, pip, a C++ compiler, and CMake are installed. + +# Exit immediately if a command exits with a non-zero status. +set -e + +# --- Configuration --- +# Specify the path to your CMake executable if it's not in the default PATH +# or if you need a specific version (like the one from snap). +# Leave empty to use the default 'cmake' found in PATH. +CMAKE_EXECUTABLE="/snap/bin/cmake" +# Project directory (assumes the script is run from the project root) +PROJECT_DIR="$(pwd)" + +# --- Prerequisite Checks --- +echo "Checking prerequisites..." + +# Check for Python 3 & pip +if ! command -v python3 &> /dev/null; then + echo "Error: python3 not found." + exit 1 +fi +if ! python3 -m pip --version &> /dev/null; then + echo "Error: pip not found for python3." + exit 1 +fi +echo "Python 3 and pip found." + +# Determine CMake command +if [ -n "$CMAKE_EXECUTABLE" ]; then + if ! command -v "$CMAKE_EXECUTABLE" &> /dev/null; then + echo "Error: Specified CMAKE_EXECUTABLE '$CMAKE_EXECUTABLE' not found." + exit 1 + fi + CMAKE_CMD="$CMAKE_EXECUTABLE" + echo "Using specified CMake: $CMAKE_CMD" +else + if ! command -v cmake &> /dev/null; then + echo "Error: cmake not found in PATH. Install CMake or set CMAKE_EXECUTABLE." + exit 1 + fi + CMAKE_CMD="cmake" + echo "Using CMake from PATH: $(command -v cmake)" +fi + +# --- Installation Steps --- +echo "Starting installation of myactuator_rmd_py..." + +# 1. Install/Upgrade pybind11 (using --user to match previous successful install) +echo "Installing/upgrading pybind11..." +python3 -m pip install --upgrade pybind11 --user + +# 2. Install the package +echo "Building and installing myactuator_rmd_py from $PROJECT_DIR..." +# Use --user install. Export CMAKE_COMMAND for the pip subprocess. +export CMAKE_COMMAND="$CMAKE_CMD" +# We keep the deprecated --global-option as it worked with the current setup.py. +# Consider updating to --config-settings if setup.py/build system is modernized. +python3 -m pip install . --user --global-option=build_ext + +echo "" +echo "Installation of myactuator_rmd_py completed successfully!" +exit 0 diff --git a/setup.py b/setup.py index c7fffa6..da94e10 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,8 @@ def build_extension(self, ext: CMakeExtension) -> None: f"-D CMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}{os.sep}", f"-D Python3_EXECUTABLE={sys.executable}", f"-D CMAKE_BUILD_TYPE={cfg}", - f"-D PYTHON_BINDINGS=on" + f"-D PYTHON_BINDINGS=on", + "-DCMAKE_POLICY_VERSION_MINIMUM=3.5" ] build_args = [] if "CMAKE_ARGS" in os.environ: diff --git a/src/can/node.cpp b/src/can/node.cpp index 0a4ec4b..9b33fb4 100644 --- a/src/can/node.cpp +++ b/src/can/node.cpp @@ -147,8 +147,13 @@ namespace myactuator_rmd { void Node::write(std::uint32_t const can_id, std::array const& data) { struct ::can_frame frame {}; frame.can_id = can_id; +#ifdef HAVE_CAN_DLC + frame.can_dlc = 8; +#else frame.len = 8; - std::copy(std::begin(data), std::end(data), std::begin(frame.data)); +#endif + memset(frame.data, 0, sizeof(frame.data)); + memcpy(frame.data, data.data(), data.size()); if (::write(socket_, &frame, sizeof(struct ::can_frame)) != sizeof(struct ::can_frame)) { std::ostringstream ss {}; ss << frame; diff --git a/src/can/utilities.cpp b/src/can/utilities.cpp index 4128230..4c55b40 100644 --- a/src/can/utilities.cpp +++ b/src/can/utilities.cpp @@ -2,15 +2,34 @@ #include #include +#include +#include #include std::ostream& operator << (std::ostream& os, struct ::can_frame const& frame) noexcept { os << "id: " << "0x" << std::hex << std::setfill('0') << std::setw(3) << frame.can_id << ", data: "; - for (int i = 0; i < frame.len; i++) { + for (int i = 0; i < frame.can_dlc; i++) { os << std::hex << std::setfill('0') << std::setw(2) << static_cast(frame.data[i]) << " "; } os << std::dec; return os; } + +std::string frameToString(can_frame const & frame) { + std::stringstream ss; + ss << "Frame -> ID: " << std::setfill(' ') << std::setw(3) << frame.can_id + << " DLC: " << static_cast(frame.can_dlc) + << " DATA:"; +#ifdef HAVE_CAN_DLC + for (int i = 0; i < frame.can_dlc; i++) { + ss << " " << std::hex << std::setfill('0') << std::setw(2) << static_cast(frame.data[i]); + } +#else + for (int i = 0; i < frame.len; i++) { + ss << " " << std::hex << std::setfill('0') << std::setw(2) << static_cast(frame.data[i]); + } +#endif + return ss.str(); +} From 5894c209f887e6cafc3beb585f3214f5e3af3085 Mon Sep 17 00:00:00 2001 From: Brian Lerner Date: Sat, 3 May 2025 20:51:47 -0400 Subject: [PATCH 2/6] adds mypy stubs --- .gitignore | 2 +- MANIFEST.in | 1 + install_myactuator_rmd.sh | 19 +-- myactuator_rmd_py.pyi | 275 ++++++++++++++++++++++++++++++++++++++ setup.py | 20 ++- 5 files changed, 306 insertions(+), 11 deletions(-) create mode 100644 MANIFEST.in create mode 100644 myactuator_rmd_py.pyi diff --git a/.gitignore b/.gitignore index 0bb42e9..742005b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ *.pyc build/ myactuator_rmd_py.egg-info/ - +dist/ diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..06c760f --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include myactuator_rmd_py.pyi diff --git a/install_myactuator_rmd.sh b/install_myactuator_rmd.sh index a7e93cc..4b2336c 100755 --- a/install_myactuator_rmd.sh +++ b/install_myactuator_rmd.sh @@ -49,17 +49,18 @@ fi # --- Installation Steps --- echo "Starting installation of myactuator_rmd_py..." -# 1. Install/Upgrade pybind11 (using --user to match previous successful install) -echo "Installing/upgrading pybind11..." -python3 -m pip install --upgrade pybind11 --user +# 1. Install/Upgrade required packages (using --user to match previous successful install) +echo "Installing/upgrading required packages..." +python3 -m pip install --upgrade pip wheel build pybind11 setuptools --user -# 2. Install the package -echo "Building and installing myactuator_rmd_py from $PROJECT_DIR..." -# Use --user install. Export CMAKE_COMMAND for the pip subprocess. +# 2. Build the wheel +echo "Building wheel for myactuator_rmd_py from $PROJECT_DIR..." export CMAKE_COMMAND="$CMAKE_CMD" -# We keep the deprecated --global-option as it worked with the current setup.py. -# Consider updating to --config-settings if setup.py/build system is modernized. -python3 -m pip install . --user --global-option=build_ext +python3 -m pip wheel . --no-deps -w dist/ + +# 3. Install the wheel +echo "Installing the wheel..." +python3 -m pip install --user --force-reinstall dist/myactuator_rmd_py*.whl echo "" echo "Installation of myactuator_rmd_py completed successfully!" diff --git a/myactuator_rmd_py.pyi b/myactuator_rmd_py.pyi new file mode 100644 index 0000000..456b760 --- /dev/null +++ b/myactuator_rmd_py.pyi @@ -0,0 +1,275 @@ +"""Python type stubs for the myactuator_rmd_py module. +Generated based on the pybind11 bindings. +""" + +import enum +from datetime import timedelta +from typing import Any, Type, Final, List, TypeVar, ClassVar + +# === Base Exceptions === + +class ActuatorException(Exception): ... + +class ProtocolException(ActuatorException): ... + +class ValueRangeException(ActuatorException): ... + +# === Base Driver Classes === + +class Driver: + # Base class, structure inferred from usage + ... + +class CanDriver(Driver): + def __init__(self, can_interface_name: str) -> None: ... + +# === Actuator State Types === + +class PiGains: + kp: int + ki: int + def __init__(self, kp: int, ki: int) -> None: ... + +class Gains: + current: PiGains + speed: PiGains + position: PiGains + def __init__(self, current: PiGains, speed: PiGains, position: PiGains) -> None: ... + # Overload for direct int initialization + # def __init__(self, current_kp: int, current_ki: int, speed_kp: int, speed_ki: int, position_kp: int, position_ki: int) -> None: ... + +class AccelerationType(enum.Enum): + POSITION_PLANNING_ACCELERATION: ClassVar[AccelerationType] + POSITION_PLANNING_DECELERATION: ClassVar[AccelerationType] + VELOCITY_PLANNING_ACCELERATION: ClassVar[AccelerationType] + VELOCITY_PLANNING_DECELERATION: ClassVar[AccelerationType] + +class CanBaudRate(enum.Enum): + KBPS500: ClassVar[CanBaudRate] + MBPS1: ClassVar[CanBaudRate] + +class ControlMode(enum.Enum): + NONE: ClassVar[ControlMode] + CURRENT: ClassVar[ControlMode] + VELOCITY: ClassVar[ControlMode] + POSITION: ClassVar[ControlMode] + +class ErrorCode(enum.Enum): + NO_ERROR: ClassVar[ErrorCode] + MOTOR_STALL: ClassVar[ErrorCode] + LOW_VOLTAGE: ClassVar[ErrorCode] + OVERVOLTAGE: ClassVar[ErrorCode] + OVERCURRENT: ClassVar[ErrorCode] + POWER_OVERRUN: ClassVar[ErrorCode] + SPEEDING: ClassVar[ErrorCode] + UNSPECIFIED_1: ClassVar[ErrorCode] + UNSPECIFIED_2: ClassVar[ErrorCode] + UNSPECIFIED_3: ClassVar[ErrorCode] + OVERTEMPERATURE: ClassVar[ErrorCode] + ENCODER_CALIBRATION_ERROR: ClassVar[ErrorCode] + +class MotorStatus1: + temperature: Final[int] + is_brake_released: Final[bool] + voltage: Final[float] + error_code: Final[ErrorCode] + def __init__(self, temperature: int, is_brake_released: bool, voltage: float, error_code: ErrorCode) -> None: ... + +class MotorStatus2: + temperature: Final[int] + current: Final[float] + shaft_speed: Final[float] + shaft_angle: Final[float] + def __init__(self, temperature: int, current: float, shaft_speed: float, shaft_angle: float) -> None: ... + +class MotorStatus3: + temperature: Final[int] + current_phase_a: Final[float] + current_phase_b: Final[float] + current_phase_c: Final[float] + def __init__(self, temperature: int, current_phase_a: float, current_phase_b: float, current_phase_c: float) -> None: ... + +# Feedback type returned by send* methods, structure mirrors MotorStatus2 +class Feedback: + temperature: Final[int] + current: Final[float] + shaft_speed: Final[float] + shaft_angle: Final[float] + # Actual __init__ might differ or not be exposed directly + def __init__(self, temperature: int, current: float, shaft_speed: float, shaft_angle: float) -> None: ... + +# === CAN Types === + +class Frame: + # Assuming std::array maps to list[int] + def __init__(self, id: int, data: List[int]) -> None: ... + def getId(self) -> int: ... + def getData(self) -> List[int]: ... + +class Node: + def __init__(self, interface_name: str) -> None: ... + # setRecvFilter takes struct can_filter*, difficult to type precisely + def setRecvFilter(self, filter: Any) -> None: ... + def read(self) -> Frame: ... + def write(self, frame: Frame) -> None: ... + +# CAN Exceptions +class SocketException(Exception): ... + +class CanException(SocketException): ... + +class TxTimeoutError(CanException): ... + +class LostArbitrationError(CanException): ... + +class ControllerProblemError(CanException): ... + +class ProtocolViolationError(CanException): ... + +class TransceiverStatusError(CanException): ... + +class NoAcknowledgeError(CanException): ... + +class BusOffError(CanException): ... + +class BusError(CanException): ... + +class ControllerRestartedError(CanException): ... + +# === Actuator Interface === + +class ActuatorInterface: + def __init__(self, driver: Driver, actuator_id: int) -> None: ... + + def getAcceleration(self) -> int: ... + def getCanId(self) -> int: ... + def getControllerGains(self) -> Gains: ... + def getControlMode(self) -> ControlMode: ... + def getMotorModel(self) -> str: ... + def getMotorPower(self) -> float: ... + def getMotorStatus1(self) -> MotorStatus1: ... + def getMotorStatus2(self) -> MotorStatus2: ... + def getMotorStatus3(self) -> MotorStatus3: ... + def getMultiTurnAngle(self) -> float: ... + def getMultiTurnEncoderPosition(self) -> int: ... + def getMultiTurnEncoderOriginalPosition(self) -> int: ... + def getMultiTurnEncoderZeroOffset(self) -> int: ... + def getRuntime(self) -> timedelta: ... + def getSingleTurnAngle(self) -> float: ... + def getSingleTurnEncoderPosition(self) -> int: ... + def getVersionDate(self) -> int: ... + + def lockBrake(self) -> None: ... + def releaseBrake(self) -> None: ... + def reset(self) -> None: ... + + def sendCurrentSetpoint(self, current: float) -> Feedback: ... + def sendPositionAbsoluteSetpoint(self, position: float, max_speed: float = 500.0) -> Feedback: ... + def sendTorqueSetpoint(self, torque: float, torque_constant: float) -> Feedback: ... + def sendVelocitySetpoint(self, speed: float) -> Feedback: ... + + def setAcceleration(self, acceleration: int, mode: AccelerationType) -> None: ... + def setCanBaudRate(self, baud_rate: CanBaudRate) -> None: ... + def setCanId(self, can_id: int) -> None: ... + def setControllerGains(self, gains: Gains, is_persistent: bool = False) -> Gains: ... + def setCurrentPositionAsEncoderZero(self) -> int: ... + def setEncoderZero(self, encoder_offset: int) -> None: ... + def setTimeout(self, timeout: timedelta) -> None: ... + def shutdownMotor(self) -> None: ... + def stopMotor(self) -> None: ... + +# === Actuator Constants === + +# Define a base class for actuator constants structure +class ActuatorConstantsBase: + reducer_ratio: Final[float] + rated_speed: Final[float] + rated_current: Final[float] + rated_power: Final[float] + rated_torque: Final[float] + torque_constant: Final[float] + rotor_inertia: Final[float] + +class X4V2(ActuatorConstantsBase): ... +class X4V3(ActuatorConstantsBase): ... +class X4_3(ActuatorConstantsBase): ... +class X4_24(ActuatorConstantsBase): ... +class X6V2(ActuatorConstantsBase): ... +class X6S2V2(ActuatorConstantsBase): ... +class X6V3(ActuatorConstantsBase): ... +class X6_7(ActuatorConstantsBase): ... +class X6_8(ActuatorConstantsBase): ... +class X6_40(ActuatorConstantsBase): ... +class X8V2(ActuatorConstantsBase): ... +class X8ProV2(ActuatorConstantsBase): ... +class X8S2V3(ActuatorConstantsBase): ... +class X8HV3(ActuatorConstantsBase): ... +class X8ProHV3(ActuatorConstantsBase): ... +class X8_20(ActuatorConstantsBase): ... +class X8_25(ActuatorConstantsBase): ... +class X8_60(ActuatorConstantsBase): ... +class X8_90(ActuatorConstantsBase): ... +class X10V3(ActuatorConstantsBase): ... +class X10S2V3(ActuatorConstantsBase): ... +class X10_40(ActuatorConstantsBase): ... +class X10_100(ActuatorConstantsBase): ... +class X12_150(ActuatorConstantsBase): ... +class X15_400(ActuatorConstantsBase): ... + + +# === Submodule Definitions === + +# Define modules that will be exposed at the top-level +class actuator_state: + AccelerationType: Type[AccelerationType] + CanBaudRate: Type[CanBaudRate] + ControlMode: Type[ControlMode] + ErrorCode: Type[ErrorCode] + PiGains: Type[PiGains] + Gains: Type[Gains] + MotorStatus1: Type[MotorStatus1] + MotorStatus2: Type[MotorStatus2] + MotorStatus3: Type[MotorStatus3] + Feedback: Type[Feedback] + +class can: + Frame: Type[Frame] + Node: Type[Node] + SocketException: Type[SocketException] + CanException: Type[CanException] + TxTimeoutError: Type[TxTimeoutError] + LostArbitrationError: Type[LostArbitrationError] + ControllerProblemError: Type[ControllerProblemError] + ProtocolViolationError: Type[ProtocolViolationError] + TransceiverStatusError: Type[TransceiverStatusError] + NoAcknowledgeError: Type[NoAcknowledgeError] + BusOffError: Type[BusOffError] + BusError: Type[BusError] + ControllerRestartedError: Type[ControllerRestartedError] + +class actuator_constants: + X4V2: Type[X4V2] + X4V3: Type[X4V3] + X4_3: Type[X4_3] + X4_24: Type[X4_24] + X6V2: Type[X6V2] + X6S2V2: Type[X6S2V2] + X6V3: Type[X6V3] + X6_7: Type[X6_7] + X6_8: Type[X6_8] + X6_40: Type[X6_40] + X8V2: Type[X8V2] + X8ProV2: Type[X8ProV2] + X8S2V3: Type[X8S2V3] + X8HV3: Type[X8HV3] + X8ProHV3: Type[X8ProHV3] + X8_20: Type[X8_20] + X8_25: Type[X8_25] + X8_60: Type[X8_60] + X8_90: Type[X8_90] + X10V3: Type[X10V3] + X10S2V3: Type[X10S2V3] + X10_40: Type[X10_40] + X10_100: Type[X10_100] + X12_150: Type[X12_150] + X15_400: Type[X15_400] diff --git a/setup.py b/setup.py index da94e10..0d97fe3 100644 --- a/setup.py +++ b/setup.py @@ -10,6 +10,7 @@ from pathlib import Path import subprocess import sys +import shutil from setuptools import Extension, setup from setuptools.command.build_ext import build_ext @@ -54,7 +55,24 @@ def build_extension(self, ext: CMakeExtension) -> None: ["cmake", "--build", ".", *build_args], cwd=build_temp, check=True ) + # Copy the .pyi file to the build directory + src_pyi = Path('myactuator_rmd_py.pyi') + dst_pyi = Path(extdir) / 'myactuator_rmd_py.pyi' + shutil.copy(src_pyi, dst_pyi) + setup( + name="myactuator_rmd_py", + version="0.2.0", + author="Tobit Flatscher", + author_email="", + description="Python bindings for MyActuator RMD actuators", + long_description="Python bindings for the MyActuator RMD actuator series using CAN communication", + url="https://github.com/2b-t/myactuator_rmd", ext_modules=[CMakeExtension("myactuator_rmd_py")], - cmdclass={"build_ext": CMakeBuild} + cmdclass={"build_ext": CMakeBuild}, + # Include .pyi files for use with type checking + package_data={"": ["*.pyi"]}, + include_package_data=True, + zip_safe=False, + python_requires=">=3.6", ) From f43e4e7e2d90098a47ed978af517ce86fba7ebba Mon Sep 17 00:00:00 2001 From: Brian Lerner Date: Sat, 3 May 2025 21:07:57 -0400 Subject: [PATCH 3/6] fixed implementation of .len vs can_dlc --- CMakeLists.txt | 5 ++--- include/myactuator_rmd/can/utilities.hpp | 1 + src/can/utilities.cpp | 19 ++++--------------- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d441d1..702df6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,11 +54,10 @@ int main() { }" HAVE_CAN_DLC) if(HAVE_CAN_DLC) - message(STATUS "Detected can_frame.can_dlc member.") + message(STATUS "Detected can_frame.can_dlc member which means we are using an older Linux CAN implementation.") target_compile_definitions(myactuator_rmd PUBLIC HAVE_CAN_DLC) else() - message(STATUS "Using can_frame.len member.") - # Assuming 'len' is the alternative, no specific define needed unless code requires it + message(STATUS "Using can_frame.len member for newer Linux CAN versions.") endif() # -------------------------------------- diff --git a/include/myactuator_rmd/can/utilities.hpp b/include/myactuator_rmd/can/utilities.hpp index 2532432..fcb88b1 100644 --- a/include/myactuator_rmd/can/utilities.hpp +++ b/include/myactuator_rmd/can/utilities.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff --git a/src/can/utilities.cpp b/src/can/utilities.cpp index 4c55b40..1573ea7 100644 --- a/src/can/utilities.cpp +++ b/src/can/utilities.cpp @@ -10,26 +10,15 @@ std::ostream& operator << (std::ostream& os, struct ::can_frame const& frame) noexcept { os << "id: " << "0x" << std::hex << std::setfill('0') << std::setw(3) << frame.can_id << ", data: "; - for (int i = 0; i < frame.can_dlc; i++) { - os << std::hex << std::setfill('0') << std::setw(2) << static_cast(frame.data[i]) << " "; - } - os << std::dec; - return os; -} - -std::string frameToString(can_frame const & frame) { - std::stringstream ss; - ss << "Frame -> ID: " << std::setfill(' ') << std::setw(3) << frame.can_id - << " DLC: " << static_cast(frame.can_dlc) - << " DATA:"; #ifdef HAVE_CAN_DLC for (int i = 0; i < frame.can_dlc; i++) { - ss << " " << std::hex << std::setfill('0') << std::setw(2) << static_cast(frame.data[i]); + os << std::hex << std::setfill('0') << std::setw(2) << static_cast(frame.data[i]) << " "; } #else for (int i = 0; i < frame.len; i++) { - ss << " " << std::hex << std::setfill('0') << std::setw(2) << static_cast(frame.data[i]); + os << std::hex << std::setfill('0') << std::setw(2) << static_cast(frame.data[i]) << " "; } #endif - return ss.str(); + os << std::dec; + return os; } From 865d90f43202fdc54e166e3be258dcf3c08491ff Mon Sep 17 00:00:00 2001 From: Brian Lerner Date: Sat, 3 May 2025 21:13:04 -0400 Subject: [PATCH 4/6] updates some comments --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 702df6d..56281df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,7 @@ int main() { }" HAVE_CAN_DLC) if(HAVE_CAN_DLC) - message(STATUS "Detected can_frame.can_dlc member which means we are using an older Linux CAN implementation.") + message(STATUS "Detected can_frame.can_dlc member - using this field name.") target_compile_definitions(myactuator_rmd PUBLIC HAVE_CAN_DLC) else() message(STATUS "Using can_frame.len member for newer Linux CAN versions.") From 9c62d9fee06cc097de15df3d7c823dacec6a2a70 Mon Sep 17 00:00:00 2001 From: Brian Lerner Date: Sat, 3 May 2025 21:18:42 -0400 Subject: [PATCH 5/6] Update include/myactuator_rmd/can/utilities.hpp --- include/myactuator_rmd/can/utilities.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/myactuator_rmd/can/utilities.hpp b/include/myactuator_rmd/can/utilities.hpp index fcb88b1..2532432 100644 --- a/include/myactuator_rmd/can/utilities.hpp +++ b/include/myactuator_rmd/can/utilities.hpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include From f645aa56f7bdd25209bbfeb8634a3cba76002b97 Mon Sep 17 00:00:00 2001 From: Brian Lerner Date: Sat, 3 May 2025 21:25:44 -0400 Subject: [PATCH 6/6] Delete install_myactuator_rmd.sh --- install_myactuator_rmd.sh | 67 --------------------------------------- 1 file changed, 67 deletions(-) delete mode 100755 install_myactuator_rmd.sh diff --git a/install_myactuator_rmd.sh b/install_myactuator_rmd.sh deleted file mode 100755 index 4b2336c..0000000 --- a/install_myactuator_rmd.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash - -# install_myactuator_rmd.sh -# Installs the myactuator_rmd_py package from the current directory. -# Assumes prerequisites like Python 3, pip, a C++ compiler, and CMake are installed. - -# Exit immediately if a command exits with a non-zero status. -set -e - -# --- Configuration --- -# Specify the path to your CMake executable if it's not in the default PATH -# or if you need a specific version (like the one from snap). -# Leave empty to use the default 'cmake' found in PATH. -CMAKE_EXECUTABLE="/snap/bin/cmake" -# Project directory (assumes the script is run from the project root) -PROJECT_DIR="$(pwd)" - -# --- Prerequisite Checks --- -echo "Checking prerequisites..." - -# Check for Python 3 & pip -if ! command -v python3 &> /dev/null; then - echo "Error: python3 not found." - exit 1 -fi -if ! python3 -m pip --version &> /dev/null; then - echo "Error: pip not found for python3." - exit 1 -fi -echo "Python 3 and pip found." - -# Determine CMake command -if [ -n "$CMAKE_EXECUTABLE" ]; then - if ! command -v "$CMAKE_EXECUTABLE" &> /dev/null; then - echo "Error: Specified CMAKE_EXECUTABLE '$CMAKE_EXECUTABLE' not found." - exit 1 - fi - CMAKE_CMD="$CMAKE_EXECUTABLE" - echo "Using specified CMake: $CMAKE_CMD" -else - if ! command -v cmake &> /dev/null; then - echo "Error: cmake not found in PATH. Install CMake or set CMAKE_EXECUTABLE." - exit 1 - fi - CMAKE_CMD="cmake" - echo "Using CMake from PATH: $(command -v cmake)" -fi - -# --- Installation Steps --- -echo "Starting installation of myactuator_rmd_py..." - -# 1. Install/Upgrade required packages (using --user to match previous successful install) -echo "Installing/upgrading required packages..." -python3 -m pip install --upgrade pip wheel build pybind11 setuptools --user - -# 2. Build the wheel -echo "Building wheel for myactuator_rmd_py from $PROJECT_DIR..." -export CMAKE_COMMAND="$CMAKE_CMD" -python3 -m pip wheel . --no-deps -w dist/ - -# 3. Install the wheel -echo "Installing the wheel..." -python3 -m pip install --user --force-reinstall dist/myactuator_rmd_py*.whl - -echo "" -echo "Installation of myactuator_rmd_py completed successfully!" -exit 0