From 508bff89406c133152d207da4aa037b722ce8608 Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Fri, 29 Aug 2025 17:16:05 +0000 Subject: [PATCH 01/17] Split socketcan adapter and socketcan adapter ros --- .../CMakeLists.txt | 19 ---- socketcan_adapter/README.md | 0 .../include}/socketcan_adapter/can_frame.hpp | 0 .../socketcan_adapter/socketcan_adapter.hpp | 0 .../launch}/socketcan_bridge_launch.py | 0 socketcan_adapter/package.xml | 17 ++++ {src => socketcan_adapter/src}/can_frame.cpp | 0 .../src}/socketcan_adapter.cpp | 0 .../test}/can_frame_test.cpp | 0 .../test}/socketcan_adapter_test.cpp | 0 socketcan_adapter_ros/CMakeLists.txt | 99 +++++++++++++++++++ socketcan_adapter_ros/README.md | 0 .../socketcan_bridge_node.hpp | 0 .../package.xml | 3 +- .../src}/socketcan_bridge.cpp | 2 +- .../src}/socketcan_bridge_node.cpp | 2 +- 16 files changed, 120 insertions(+), 22 deletions(-) rename CMakeLists.txt => socketcan_adapter/CMakeLists.txt (86%) create mode 100644 socketcan_adapter/README.md rename {include => socketcan_adapter/include}/socketcan_adapter/can_frame.hpp (100%) rename {include => socketcan_adapter/include}/socketcan_adapter/socketcan_adapter.hpp (100%) rename {launch => socketcan_adapter/launch}/socketcan_bridge_launch.py (100%) create mode 100644 socketcan_adapter/package.xml rename {src => socketcan_adapter/src}/can_frame.cpp (100%) rename {src => socketcan_adapter/src}/socketcan_adapter.cpp (100%) rename {test => socketcan_adapter/test}/can_frame_test.cpp (100%) rename {test => socketcan_adapter/test}/socketcan_adapter_test.cpp (100%) create mode 100644 socketcan_adapter_ros/CMakeLists.txt create mode 100644 socketcan_adapter_ros/README.md rename {include/socketcan_adapter => socketcan_adapter_ros/include/socketcan_adapter_ros}/socketcan_bridge_node.hpp (100%) rename package.xml => socketcan_adapter_ros/package.xml (90%) rename {src => socketcan_adapter_ros/src}/socketcan_bridge.cpp (95%) rename {src => socketcan_adapter_ros/src}/socketcan_bridge_node.cpp (99%) diff --git a/CMakeLists.txt b/socketcan_adapter/CMakeLists.txt similarity index 86% rename from CMakeLists.txt rename to socketcan_adapter/CMakeLists.txt index 15448d7..75051ed 100644 --- a/CMakeLists.txt +++ b/socketcan_adapter/CMakeLists.txt @@ -49,14 +49,10 @@ endif() # Dependencies find_package(ament_cmake REQUIRED) -find_package(rclcpp REQUIRED) -find_package(rclcpp_lifecycle REQUIRED) -find_package(can_msgs REQUIRED) # Primary library add_library(socketcan_adapter SHARED src/socketcan_adapter.cpp - src/socketcan_bridge_node.cpp src/can_frame.cpp ) target_include_directories(socketcan_adapter PUBLIC @@ -65,20 +61,6 @@ target_include_directories(socketcan_adapter PUBLIC ) target_compile_definitions(socketcan_adapter PRIVATE "SOCKETCAN_ADAPTER_BUILDING_LIBRARY") -# Executable using the library -add_executable(socketcan_bridge src/socketcan_bridge.cpp) -target_include_directories(socketcan_bridge PUBLIC - $ - $ -) - -target_link_libraries(socketcan_adapter PUBLIC - ${can_msgs_TARGETS} - rclcpp::rclcpp - rclcpp_lifecycle::rclcpp_lifecycle -) -target_link_libraries(socketcan_bridge PUBLIC socketcan_adapter) - # Installs install(DIRECTORY include/ DESTINATION include) install(TARGETS socketcan_adapter @@ -87,7 +69,6 @@ install(TARGETS socketcan_adapter LIBRARY DESTINATION lib RUNTIME DESTINATION bin ) -install(TARGETS socketcan_bridge DESTINATION lib/${PROJECT_NAME}) install(EXPORT ${PROJECT_NAME}_TARGETS NAMESPACE ${PROJECT_NAME}:: DESTINATION share/${PROJECT_NAME}/cmake diff --git a/socketcan_adapter/README.md b/socketcan_adapter/README.md new file mode 100644 index 0000000..e69de29 diff --git a/include/socketcan_adapter/can_frame.hpp b/socketcan_adapter/include/socketcan_adapter/can_frame.hpp similarity index 100% rename from include/socketcan_adapter/can_frame.hpp rename to socketcan_adapter/include/socketcan_adapter/can_frame.hpp diff --git a/include/socketcan_adapter/socketcan_adapter.hpp b/socketcan_adapter/include/socketcan_adapter/socketcan_adapter.hpp similarity index 100% rename from include/socketcan_adapter/socketcan_adapter.hpp rename to socketcan_adapter/include/socketcan_adapter/socketcan_adapter.hpp diff --git a/launch/socketcan_bridge_launch.py b/socketcan_adapter/launch/socketcan_bridge_launch.py similarity index 100% rename from launch/socketcan_bridge_launch.py rename to socketcan_adapter/launch/socketcan_bridge_launch.py diff --git a/socketcan_adapter/package.xml b/socketcan_adapter/package.xml new file mode 100644 index 0000000..af211a9 --- /dev/null +++ b/socketcan_adapter/package.xml @@ -0,0 +1,17 @@ + + + + socketcan_adapter + 0.1.0 + An Adapter Library for Socketcan using Callback Patterns + Polymath Engineering + Apache-2.0 + Zeerek Ahmad + + ament_cmake_test + catch2 + + + ament_cmake + + diff --git a/src/can_frame.cpp b/socketcan_adapter/src/can_frame.cpp similarity index 100% rename from src/can_frame.cpp rename to socketcan_adapter/src/can_frame.cpp diff --git a/src/socketcan_adapter.cpp b/socketcan_adapter/src/socketcan_adapter.cpp similarity index 100% rename from src/socketcan_adapter.cpp rename to socketcan_adapter/src/socketcan_adapter.cpp diff --git a/test/can_frame_test.cpp b/socketcan_adapter/test/can_frame_test.cpp similarity index 100% rename from test/can_frame_test.cpp rename to socketcan_adapter/test/can_frame_test.cpp diff --git a/test/socketcan_adapter_test.cpp b/socketcan_adapter/test/socketcan_adapter_test.cpp similarity index 100% rename from test/socketcan_adapter_test.cpp rename to socketcan_adapter/test/socketcan_adapter_test.cpp diff --git a/socketcan_adapter_ros/CMakeLists.txt b/socketcan_adapter_ros/CMakeLists.txt new file mode 100644 index 0000000..20f70f6 --- /dev/null +++ b/socketcan_adapter_ros/CMakeLists.txt @@ -0,0 +1,99 @@ +# Copyright (c) 2025-present Polymath Robotics, Inc. All rights reserved +# +# 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. + +cmake_minimum_required(VERSION 3.8) +project(socketcan_adapter_ros) + +# Project-wide language standards +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +# Warnings & link hygiene +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) + add_link_options(-Wl,-no-undefined) +endif() + +# Enable ASAN in Debug builds +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + message(STATUS "Enabling AddressSanitizer (ASAN) for Debug build") + set(ASAN_FLAGS "-fsanitize=address -fno-omit-frame-pointer") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ASAN_FLAGS}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ASAN_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ASAN_FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${ASAN_FLAGS}") +endif() + +# Distro detection (override with -BUILD_HUMBLE=ON/OFF) +if(NOT DEFINED BUILD_HUMBLE) + if(DEFINED ENV{ROS_DISTRO} AND "$ENV{ROS_DISTRO}" STREQUAL "humble") + set(BUILD_HUMBLE TRUE) + message(STATUS "ROS_DISTRO=humble -> using Catch2 v2") + else() + set(BUILD_HUMBLE FALSE) + message(STATUS "ROS_DISTRO>humble -> Catch2 v3 (Jazzy/Rolling)") + endif() +endif() + +# Dependencies +find_package(ament_cmake REQUIRED) +find_package(rclcpp REQUIRED) +find_package(rclcpp_lifecycle REQUIRED) +find_package(can_msgs REQUIRED) +find_package(socketcan_adapter REQUIRED) + +# Primary library +add_library(socketcan_adapter_ros SHARED + src/socketcan_bridge_node.cpp +) +target_include_directories(socketcan_adapter_ros PUBLIC + $ + $ +) +target_compile_definitions(socketcan_adapter_ros PRIVATE "SOCKETCAN_ADAPTER_ROS_BUILDING_LIBRARY") + +# Executable using the library +add_executable(socketcan_bridge src/socketcan_bridge.cpp) +target_include_directories(socketcan_bridge PUBLIC + $ + $ +) + +target_link_libraries(socketcan_adapter_ros PUBLIC + ${can_msgs_TARGETS} + rclcpp::rclcpp + rclcpp_lifecycle::rclcpp_lifecycle + socketcan_adapter::socketcan_adapter +) +target_link_libraries(socketcan_bridge PUBLIC socketcan_adapter_ros) + +# Installs +install(DIRECTORY include/ DESTINATION include) +install(TARGETS socketcan_adapter_ros + EXPORT ${PROJECT_NAME}_TARGETS + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) +install(TARGETS socketcan_bridge DESTINATION lib/${PROJECT_NAME}) +install(EXPORT ${PROJECT_NAME}_TARGETS + NAMESPACE ${PROJECT_NAME}:: + DESTINATION share/${PROJECT_NAME}/cmake +) + +# Export +ament_export_targets(${PROJECT_NAME}_TARGETS HAS_LIBRARY_TARGET) +ament_export_dependencies(socketcan_adapter rclcpp rclcpp_lifecycle can_msgs) +ament_package() diff --git a/socketcan_adapter_ros/README.md b/socketcan_adapter_ros/README.md new file mode 100644 index 0000000..e69de29 diff --git a/include/socketcan_adapter/socketcan_bridge_node.hpp b/socketcan_adapter_ros/include/socketcan_adapter_ros/socketcan_bridge_node.hpp similarity index 100% rename from include/socketcan_adapter/socketcan_bridge_node.hpp rename to socketcan_adapter_ros/include/socketcan_adapter_ros/socketcan_bridge_node.hpp diff --git a/package.xml b/socketcan_adapter_ros/package.xml similarity index 90% rename from package.xml rename to socketcan_adapter_ros/package.xml index e945324..7831a80 100644 --- a/package.xml +++ b/socketcan_adapter_ros/package.xml @@ -1,7 +1,7 @@ - socketcan_adapter + socketcan_adapter_ros 0.1.0 An Adapter Library for Socketcan with ROS2 Polymath Engineering @@ -11,6 +11,7 @@ rclcpp rclcpp_lifecycle can_msgs + socketcan_adapter ament_cmake_test catch2 diff --git a/src/socketcan_bridge.cpp b/socketcan_adapter_ros/src/socketcan_bridge.cpp similarity index 95% rename from src/socketcan_bridge.cpp rename to socketcan_adapter_ros/src/socketcan_bridge.cpp index 2529f2f..9d9cfba 100644 --- a/src/socketcan_bridge.cpp +++ b/socketcan_adapter_ros/src/socketcan_bridge.cpp @@ -17,7 +17,7 @@ #include "rclcpp/rclcpp.hpp" #include "rclcpp_lifecycle/lifecycle_node.hpp" -#include "socketcan_adapter/socketcan_bridge_node.hpp" +#include "socketcan_adapter_ros/socketcan_bridge_node.hpp" #include "std_msgs/msg/string.hpp" int main(int argc, char ** argv) diff --git a/src/socketcan_bridge_node.cpp b/socketcan_adapter_ros/src/socketcan_bridge_node.cpp similarity index 99% rename from src/socketcan_bridge_node.cpp rename to socketcan_adapter_ros/src/socketcan_bridge_node.cpp index b4162f9..e770ac6 100644 --- a/src/socketcan_bridge_node.cpp +++ b/socketcan_adapter_ros/src/socketcan_bridge_node.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "socketcan_adapter/socketcan_bridge_node.hpp" +#include "socketcan_adapter_ros/socketcan_bridge_node.hpp" #include #include From 845c0803c07abb7413044968aa08a5b21227cba7 Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Fri, 29 Aug 2025 17:21:53 +0000 Subject: [PATCH 02/17] Update readmes via guided AI (prior to cleanup) and pre-commit --- README.md | 205 +++++++++--------- socketcan_adapter/README.md | 148 +++++++++++++ .../launch/socketcan_bridge_launch.py | 9 +- socketcan_adapter_ros/README.md | 134 ++++++++++++ 4 files changed, 390 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index 2ce6e4e..38765d7 100644 --- a/README.md +++ b/README.md @@ -1,129 +1,132 @@ -# socketcan_adapter -Socketcan Driver Library for Linux based PCs and ROS2 nodes +# SocketCAN Adapter -# Build -Socketcan adapter can be built with the ros2 ament toolchain. All requirements can be installed via rosdep +A modular SocketCAN driver library and ROS2 integration for Linux-based systems. This repository provides both a standalone C++ library and ROS2 wrapper for easy integration with robotics applications. -Install the dependencies! +## Architecture + +This package is split into two complementary components: + +### 📚 [socketcan_adapter](./socketcan_adapter/README.md) +Pure C++ SocketCAN library with no ROS dependencies. +- Core SocketCAN functionality +- Thread-safe operations +- Callback-based asynchronous processing +- Configurable filters and error handling +- Can be used in non-ROS projects + +### 🤖 [socketcan_adapter_ros](./socketcan_adapter_ros/README.md) +ROS2 wrapper providing nodes and launch files. +- ROS2 lifecycle node +- Integration with `can_msgs` +- Launch files with parameter support +- Depends on the core `socketcan_adapter` library + +## Quick Start + +### Build Both Packages ```bash -rosdep install -i -y --from-paths socketcan_adapter +# Install dependencies +rosdep install -i -y --from-paths . + +# Build everything +colcon build --packages-up-to socketcan_adapter_ros ``` -Build it! +### Launch ROS2 CAN Bridge ```bash -colcon build --packages-up-to socketcan_adapter +ros2 launch socketcan_adapter_ros socketcan_bridge_launch.py ``` -# Library -## Classes of Note -### CanFrame -`CanFrame` Class - This class wraps the C-level `can_frame` structure, encapsulating CAN message details like the CAN ID, data, timestamp, and frame type (DATA, ERROR, or REMOTE). By providing a robust API for creating and managing CAN frames, CanFrame simplifies interaction with raw CAN data and offers utilities like ID masking, setting error types, and timestamp management. +### Use Core Library in C++ -Example highlights: +```c++ +#include "socketcan_adapter/socketcan_adapter.hpp" -- Flexible constructors for `can_frame` struct and raw data inputs. -- Functions to modify frame type, ID type (standard/extended), and length. -- Helper methods to access CAN frame data, ID, and timestamp. +using namespace polymath::socketcan; -Does not implement CanFD yet. +SocketcanAdapter adapter("can0"); +adapter.openSocket(); +// ... see socketcan_adapter README for full example +``` -### SocketcanAdapter -`SocketcanAdapter` Class - The `SocketcanAdapter` abstracts and manages socket operations for CAN communication. It initializes and configures the socket, applies filters, and handles CAN frame transmission and reception. The adapter offers error handling, thread-safe operations, and optional callback functions for asynchronous frame and error processing. +## Requirements -Key features: +### System Requirements +- Linux with SocketCAN support +- C++17 compatible compiler +- CMake 3.8+ -- Configurable receive timeout and threading for reception. -- `setFilters` and setErrorMaskOverwrite to apply CAN filters and error masks. -- A callback-based system for handling received frames and errors asynchronously. -- Supports multiple send and receive methods, including `std::shared_ptr` for efficient memory management. -- Together, `CanFrame` and `SocketcanAdapter` simplify interaction with CAN networks, allowing developers to focus on - high-level application logic instead of low-level socket and data handling. +### ROS2 Requirements (for ROS package only) +- ROS2 Humble or later +- can_msgs package -## Sample Usage +## Testing -```c++ -#include "socketcan_adapter/socketcan_adapter.hpp" -#include "socketcan_adapter/can_frame.hpp" -#include -#include -#include +### Core Library Tests -using namespace polymath::socketcan; +```bash +colcon test --packages-select socketcan_adapter +``` -int main() { - // Initialize SocketcanAdapter with the CAN interface name (e.g., "can0") - SocketcanAdapter adapter("can0"); - - // Open the CAN socket - if (!adapter.openSocket()) { - std::cerr << "Failed to open CAN socket!" << std::endl; - return -1; - } - - // Step 1: Set up a filter to allow only messages with ID 0x123 - std::vector filters = {{0x123, CAN_SFF_MASK}}; - if (auto error = adapter.setFilters(filters)) { - std::cerr << "Error setting filters: " << *error << std::endl; - return -1; - } - - // Step 2: Set up a callback function to handle received CAN frames - adapter.setOnReceiveCallback([](std::unique_ptr frame) { - std::cout << "Received CAN frame with ID: " << std::hex << frame->get_id() << std::endl; - auto data = frame->get_data(); - std::cout << "Data: "; - for (const auto& byte : data) { - std::cout << std::hex << static_cast(byte) << " "; - } - std::cout << std::endl; - }); - - // Step 3: Start the reception thread - if (!adapter.startReceptionThread()) { - std::cerr << "Failed to start reception thread!" << std::endl; - adapter.closeSocket(); - return -1; - } - - // Step 4: Prepare a CAN frame to send - canid_t raw_id = 0x123; - std::array data = {0x11, 0x22, 0x33, 0x44}; - uint64_t timestamp = 0; // Placeholder timestamp - CanFrame frame(raw_id, data, timestamp); - - // Step 5: Send the CAN frame - if (auto error = adapter.send(frame)) { - std::cerr << "Failed to send CAN frame: " << *error << std::endl; - } else { - std::cout << "Sent CAN frame with ID: " << std::hex << raw_id << std::endl; - } - - // Keep the application running for 10 seconds to allow for frame reception - std::this_thread::sleep_for(std::chrono::seconds(10)); - - // Step 5: Clean up - close the socket and stop the reception thread - adapter.joinReceptionThread(); - adapter.closeSocket(); - - return 0; -} +### ROS2 Package Tests +```bash +colcon test --packages-select socketcan_adapter_ros ``` -# ROS2 Node -To make usage even easier, this package comes with a ROS2 node with default settings! +### Hardware Tests +Set `CAN_AVAILABLE=1` to enable hardware-dependent tests: -## Launch +```bash +CAN_AVAILABLE=1 colcon test --packages-select socketcan_adapter +``` + +## Virtual CAN Setup + +For testing without hardware: ```bash -ros2 launch socketcan_adapter socketcan_bridge_launch.py +sudo modprobe vcan +sudo ip link add dev vcan0 type vcan +sudo ip link set up vcan0 ``` -launch args: -- `can_interface`: can interface to connect to (default: 0) -- `can_error_mask`: can error mask (default: 0x1FFFFFFF aka everything allowed) -- `can_filter_list`: can filters (default: []) -- `join_filters`: use joining logic for filters (default: false) -- `auto_configure`: automatically configure the lifecycle node -- `auto_activate`: automatically activate the lifecycle node post configuration +## Contributing + +We welcome contributions! Please see our [contributing guidelines](CONTRIBUTING.md) for details on: +- Code style and standards +- Testing requirements +- Pull request process +- Issue reporting + +## Changelog + +See [CHANGELOG.md](CHANGELOG.md) for a detailed history of changes. + +## Support + +- 📖 **Documentation**: See individual package READMEs for detailed usage +- 🐛 **Bug Reports**: Please use GitHub Issues with detailed reproduction steps +- 💡 **Feature Requests**: Open a GitHub Issue with your use case +- 📧 **Contact**: engineering@polymathrobotics.com + +## Security + +If you discover a security vulnerability, please send an email to security@polymathrobotics.com. All security vulnerabilities will be promptly addressed. + +## License + +Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for the full license text. + +## Authors & Maintainers + +- **Zeerek Ahmad** - Original author - zeerekahmad@hotmail.com +- **Polymath Robotics Engineering Team** - Maintainers - engineering@polymathrobotics.com + +## Acknowledgments + +- Linux SocketCAN developers for the underlying CAN bus support +- ROS2 community for the robotics middleware framework +- Contributors and users who help improve this project diff --git a/socketcan_adapter/README.md b/socketcan_adapter/README.md index e69de29..5e035bd 100644 --- a/socketcan_adapter/README.md +++ b/socketcan_adapter/README.md @@ -0,0 +1,148 @@ +# socketcan_adapter + +A pure C++ SocketCAN driver library for Linux-based systems. This library provides a high-level interface to Linux SocketCAN without any ROS dependencies. + +## Features + +- Pure C++ implementation with no ROS runtime dependencies +- Thread-safe CAN frame transmission and reception +- Configurable filters and error masks +- Callback-based asynchronous processing +- Comprehensive error handling +- Support for standard and extended CAN IDs + +## Classes of Note + +### CanFrame +`CanFrame` Class - This class wraps the C-level `can_frame` structure, encapsulating CAN message details like the CAN ID, data, timestamp, and frame type (DATA, ERROR, or REMOTE). By providing a robust API for creating and managing CAN frames, CanFrame simplifies interaction with raw CAN data and offers utilities like ID masking, setting error types, and timestamp management. + +Example highlights: + +- Flexible constructors for `can_frame` struct and raw data inputs. +- Functions to modify frame type, ID type (standard/extended), and length. +- Helper methods to access CAN frame data, ID, and timestamp. + +Does not implement CanFD yet. + +### SocketcanAdapter +`SocketcanAdapter` Class - The `SocketcanAdapter` abstracts and manages socket operations for CAN communication. It initializes and configures the socket, applies filters, and handles CAN frame transmission and reception. The adapter offers error handling, thread-safe operations, and optional callback functions for asynchronous frame and error processing. + +Key features: + +- Configurable receive timeout and threading for reception. +- `setFilters` and setErrorMaskOverwrite to apply CAN filters and error masks. +- A callback-based system for handling received frames and errors asynchronously. +- Supports multiple send and receive methods, including `std::shared_ptr` for efficient memory management. +- Together, `CanFrame` and `SocketcanAdapter` simplify interaction with CAN networks, allowing developers to focus on high-level application logic instead of low-level socket and data handling. + +## Build + +This package can be built with the ROS2 ament toolchain or as a standalone CMake project. + +### ROS2 Build +Install dependencies: + +```bash +rosdep install -i -y --from-paths socketcan_adapter +``` + +Build: + +```bash +colcon build --packages-select socketcan_adapter +``` + +### Standalone CMake Build + +```bash +mkdir build && cd build +cmake .. +make +``` + +## Sample Usage + +```c++ +#include "socketcan_adapter/socketcan_adapter.hpp" +#include "socketcan_adapter/can_frame.hpp" +#include +#include +#include + +using namespace polymath::socketcan; + +int main() { + // Initialize SocketcanAdapter with the CAN interface name (e.g., "can0") + SocketcanAdapter adapter("can0"); + + // Open the CAN socket + if (!adapter.openSocket()) { + std::cerr << "Failed to open CAN socket!" << std::endl; + return -1; + } + + // Step 1: Set up a filter to allow only messages with ID 0x123 + std::vector filters = {{0x123, CAN_SFF_MASK}}; + if (auto error = adapter.setFilters(filters)) { + std::cerr << "Error setting filters: " << *error << std::endl; + return -1; + } + + // Step 2: Set up a callback function to handle received CAN frames + adapter.setOnReceiveCallback([](std::unique_ptr frame) { + std::cout << "Received CAN frame with ID: " << std::hex << frame->get_id() << std::endl; + auto data = frame->get_data(); + std::cout << "Data: "; + for (const auto& byte : data) { + std::cout << std::hex << static_cast(byte) << " "; + } + std::cout << std::endl; + }); + + // Step 3: Start the reception thread + if (!adapter.startReceptionThread()) { + std::cerr << "Failed to start reception thread!" << std::endl; + adapter.closeSocket(); + return -1; + } + + // Step 4: Prepare a CAN frame to send + canid_t raw_id = 0x123; + std::array data = {0x11, 0x22, 0x33, 0x44}; + uint64_t timestamp = 0; // Placeholder timestamp + CanFrame frame(raw_id, data, timestamp); + + // Step 5: Send the CAN frame + if (auto error = adapter.send(frame)) { + std::cerr << "Failed to send CAN frame: " << *error << std::endl; + } else { + std::cout << "Sent CAN frame with ID: " << std::hex << raw_id << std::endl; + } + + // Keep the application running for 10 seconds to allow for frame reception + std::this_thread::sleep_for(std::chrono::seconds(10)); + + // Step 5: Clean up - close the socket and stop the reception thread + adapter.joinReceptionThread(); + adapter.closeSocket(); + + return 0; +} +``` + +## Testing + +Run tests: + +```bash +colcon test --packages-select socketcan_adapter +``` + +Note: Hardware tests require `CAN_AVAILABLE=1` environment variable and a functioning CAN interface. + +## Requirements + +- Linux system with SocketCAN support +- C++17 compatible compiler +- CMake 3.8+ +- Catch2 (for testing) diff --git a/socketcan_adapter/launch/socketcan_bridge_launch.py b/socketcan_adapter/launch/socketcan_bridge_launch.py index 8c72920..b2a7c64 100644 --- a/socketcan_adapter/launch/socketcan_bridge_launch.py +++ b/socketcan_adapter/launch/socketcan_bridge_launch.py @@ -28,17 +28,16 @@ # Co-developed by Tier IV, Inc. and Apex.AI, Inc. -from launch_ros.actions import LifecycleNode -from launch_ros.event_handlers import OnStateTransition -from launch_ros.events.lifecycle import ChangeState -from lifecycle_msgs.msg import Transition - from launch import LaunchDescription from launch.actions import DeclareLaunchArgument, EmitEvent, RegisterEventHandler from launch.conditions import IfCondition from launch.event_handlers import OnProcessStart from launch.events import matches_action from launch.substitutions import LaunchConfiguration +from launch_ros.actions import LifecycleNode +from launch_ros.event_handlers import OnStateTransition +from launch_ros.events.lifecycle import ChangeState +from lifecycle_msgs.msg import Transition def generate_launch_description(): diff --git a/socketcan_adapter_ros/README.md b/socketcan_adapter_ros/README.md index e69de29..e25a7c4 100644 --- a/socketcan_adapter_ros/README.md +++ b/socketcan_adapter_ros/README.md @@ -0,0 +1,134 @@ +# socketcan_adapter_ros + +A ROS2 wrapper for the socketcan_adapter library, providing ROS2 nodes and launch files for easy integration with ROS2 systems. + +## Features + +- ROS2 lifecycle node for CAN bridge functionality +- Publishes received CAN frames as `can_msgs/msg/Frame` +- Subscribes to CAN frames for transmission +- Configurable CAN interface, filters, and error masks +- Launch file with comprehensive parameter support +- Integration with ROS2 parameter system + +## Dependencies + +- [socketcan_adapter](../socketcan_adapter/README.md) - Core SocketCAN library +- rclcpp - ROS2 C++ client library +- rclcpp_lifecycle - ROS2 lifecycle node support +- can_msgs - ROS2 CAN message definitions + +## Build + +Install dependencies: + +```bash +rosdep install -i -y --from-paths socketcan_adapter_ros +``` + +Build: + +```bash +colcon build --packages-up-to socketcan_adapter_ros +``` + +## Usage + +### Launch the CAN Bridge Node + +```bash +ros2 launch socketcan_adapter_ros socketcan_bridge_launch.py +``` + +### Launch Parameters + +- `can_interface`: CAN interface to connect to (default: "can0") +- `can_error_mask`: CAN error mask (default: 0x1FFFFFFF - everything allowed) +- `can_filter_list`: CAN filters as list of ID/mask pairs (default: []) +- `join_filters`: Use joining logic for filters (default: false) +- `auto_configure`: Automatically configure the lifecycle node (default: true) +- `auto_activate`: Automatically activate the lifecycle node post configuration (default: true) + +### Example Launch with Parameters + +```bash +ros2 launch socketcan_adapter_ros socketcan_bridge_launch.py \ + can_interface:=can1 \ + can_error_mask:=0x1F \ + can_filter_list:="[{id: 0x123, mask: 0x7FF}, {id: 0x456, mask: 0x7FF}]" +``` + +### Manual Lifecycle Management + +If you prefer manual control over the lifecycle: + +```bash +# Launch without auto-activation +ros2 launch socketcan_adapter_ros socketcan_bridge_launch.py \ + auto_configure:=false \ + auto_activate:=false + +# Configure the node +ros2 lifecycle set /socketcan_bridge configure + +# Activate the node +ros2 lifecycle set /socketcan_bridge activate +``` + +## Topics + +### Published Topics + +- `/can_rx` (`can_msgs/msg/Frame`) - Received CAN frames from the bus + +### Subscribed Topics + +- `/can_tx` (`can_msgs/msg/Frame`) - CAN frames to transmit to the bus + +## Node Details + +The `socketcan_bridge` node is implemented as a ROS2 lifecycle node, providing the following states: + +1. **Unconfigured** - Initial state +2. **Inactive** - Node is configured but not processing messages +3. **Active** - Node is actively bridging CAN messages +4. **Finalized** - Node is shut down + +### Parameters + +The node accepts the following ROS2 parameters: + +- `can_interface` (string): Name of the CAN interface (e.g., "can0", "vcan0") +- `error_mask` (int): CAN error mask for filtering error frames +- `filters` (array): List of CAN filter objects with `id` and `mask` fields +- `join_filters` (bool): Whether to use joining logic for multiple filters + +## Testing + +Run tests: + +```bash +colcon test --packages-select socketcan_adapter_ros +``` + +## Requirements + +- ROS2 (Humble or later) +- Linux system with SocketCAN support +- [socketcan_adapter](../socketcan_adapter/README.md) library +- Active CAN interface (real or virtual) + +## Creating Virtual CAN Interface + +For testing without hardware: + +```bash +# Load the vcan module +sudo modprobe vcan + +# Create a virtual CAN interface +sudo ip link add dev vcan0 type vcan + +# Bring up the interface +sudo ip link set up vcan0 +``` From db870da1d6cb5fcf8f6db30cd1286b2bbd1510d7 Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Fri, 29 Aug 2025 17:23:22 +0000 Subject: [PATCH 03/17] Cleanup top level readme.md --- README.md | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/README.md b/README.md index 38765d7..48d002c 100644 --- a/README.md +++ b/README.md @@ -70,12 +70,6 @@ adapter.openSocket(); colcon test --packages-select socketcan_adapter ``` -### ROS2 Package Tests - -```bash -colcon test --packages-select socketcan_adapter_ros -``` - ### Hardware Tests Set `CAN_AVAILABLE=1` to enable hardware-dependent tests: @@ -93,29 +87,6 @@ sudo ip link add dev vcan0 type vcan sudo ip link set up vcan0 ``` -## Contributing - -We welcome contributions! Please see our [contributing guidelines](CONTRIBUTING.md) for details on: -- Code style and standards -- Testing requirements -- Pull request process -- Issue reporting - -## Changelog - -See [CHANGELOG.md](CHANGELOG.md) for a detailed history of changes. - -## Support - -- 📖 **Documentation**: See individual package READMEs for detailed usage -- 🐛 **Bug Reports**: Please use GitHub Issues with detailed reproduction steps -- 💡 **Feature Requests**: Open a GitHub Issue with your use case -- 📧 **Contact**: engineering@polymathrobotics.com - -## Security - -If you discover a security vulnerability, please send an email to security@polymathrobotics.com. All security vulnerabilities will be promptly addressed. - ## License Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for the full license text. @@ -124,9 +95,3 @@ Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for the f - **Zeerek Ahmad** - Original author - zeerekahmad@hotmail.com - **Polymath Robotics Engineering Team** - Maintainers - engineering@polymathrobotics.com - -## Acknowledgments - -- Linux SocketCAN developers for the underlying CAN bus support -- ROS2 community for the robotics middleware framework -- Contributors and users who help improve this project From 20a418c0cb2f7029ea79b8550add3dc468ea01dd Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Fri, 29 Aug 2025 11:46:12 -0700 Subject: [PATCH 04/17] Update README.md Remove emojis --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 48d002c..1c82b3e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A modular SocketCAN driver library and ROS2 integration for Linux-based systems. This package is split into two complementary components: -### 📚 [socketcan_adapter](./socketcan_adapter/README.md) +### [socketcan_adapter](./socketcan_adapter/README.md) Pure C++ SocketCAN library with no ROS dependencies. - Core SocketCAN functionality - Thread-safe operations @@ -14,7 +14,7 @@ Pure C++ SocketCAN library with no ROS dependencies. - Configurable filters and error handling - Can be used in non-ROS projects -### 🤖 [socketcan_adapter_ros](./socketcan_adapter_ros/README.md) +### [socketcan_adapter_ros](./socketcan_adapter_ros/README.md) ROS2 wrapper providing nodes and launch files. - ROS2 lifecycle node - Integration with `can_msgs` From 2bc364425a8252c463c01a5385a606d8a93b5253 Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Fri, 29 Aug 2025 11:53:38 -0700 Subject: [PATCH 05/17] Further clean up readmes --- socketcan_adapter/README.md | 32 +++++++++++++-------------- socketcan_adapter_ros/README.md | 39 +-------------------------------- 2 files changed, 17 insertions(+), 54 deletions(-) diff --git a/socketcan_adapter/README.md b/socketcan_adapter/README.md index 5e035bd..7ff2800 100644 --- a/socketcan_adapter/README.md +++ b/socketcan_adapter/README.md @@ -1,15 +1,6 @@ # socketcan_adapter -A pure C++ SocketCAN driver library for Linux-based systems. This library provides a high-level interface to Linux SocketCAN without any ROS dependencies. - -## Features - -- Pure C++ implementation with no ROS runtime dependencies -- Thread-safe CAN frame transmission and reception -- Configurable filters and error masks -- Callback-based asynchronous processing -- Comprehensive error handling -- Support for standard and extended CAN IDs +A C++ SocketCAN driver library for Linux-based systems. This library provides a high-level interface to Linux SocketCAN without any ROS dependencies. ## Classes of Note @@ -20,7 +11,7 @@ Example highlights: - Flexible constructors for `can_frame` struct and raw data inputs. - Functions to modify frame type, ID type (standard/extended), and length. -- Helper methods to access CAN frame data, ID, and timestamp. +- Helper methods to access CAN frame data, ID. Does not implement CanFD yet. @@ -140,9 +131,18 @@ colcon test --packages-select socketcan_adapter Note: Hardware tests require `CAN_AVAILABLE=1` environment variable and a functioning CAN interface. -## Requirements -- Linux system with SocketCAN support -- C++17 compatible compiler -- CMake 3.8+ -- Catch2 (for testing) +### Creating Virtual CAN Interface + +For testing without hardware: + +```bash +# Load the vcan module +sudo modprobe vcan + +# Create a virtual CAN interface +sudo ip link add dev vcan0 type vcan + +# Bring up the interface +sudo ip link set up vcan0 +``` diff --git a/socketcan_adapter_ros/README.md b/socketcan_adapter_ros/README.md index e25a7c4..41e41bd 100644 --- a/socketcan_adapter_ros/README.md +++ b/socketcan_adapter_ros/README.md @@ -2,15 +2,6 @@ A ROS2 wrapper for the socketcan_adapter library, providing ROS2 nodes and launch files for easy integration with ROS2 systems. -## Features - -- ROS2 lifecycle node for CAN bridge functionality -- Publishes received CAN frames as `can_msgs/msg/Frame` -- Subscribes to CAN frames for transmission -- Configurable CAN interface, filters, and error masks -- Launch file with comprehensive parameter support -- Integration with ROS2 parameter system - ## Dependencies - [socketcan_adapter](../socketcan_adapter/README.md) - Core SocketCAN library @@ -87,12 +78,7 @@ ros2 lifecycle set /socketcan_bridge activate ## Node Details -The `socketcan_bridge` node is implemented as a ROS2 lifecycle node, providing the following states: - -1. **Unconfigured** - Initial state -2. **Inactive** - Node is configured but not processing messages -3. **Active** - Node is actively bridging CAN messages -4. **Finalized** - Node is shut down +The `socketcan_bridge` node is implemented as a ROS2 lifecycle node ### Parameters @@ -103,32 +89,9 @@ The node accepts the following ROS2 parameters: - `filters` (array): List of CAN filter objects with `id` and `mask` fields - `join_filters` (bool): Whether to use joining logic for multiple filters -## Testing - -Run tests: - -```bash -colcon test --packages-select socketcan_adapter_ros -``` - ## Requirements - ROS2 (Humble or later) - Linux system with SocketCAN support - [socketcan_adapter](../socketcan_adapter/README.md) library - Active CAN interface (real or virtual) - -## Creating Virtual CAN Interface - -For testing without hardware: - -```bash -# Load the vcan module -sudo modprobe vcan - -# Create a virtual CAN interface -sudo ip link add dev vcan0 type vcan - -# Bring up the interface -sudo ip link set up vcan0 -``` From 3402301ec372aac31a660e6b706bee3a706337aa Mon Sep 17 00:00:00 2001 From: Zeerek Date: Fri, 29 Aug 2025 19:22:33 +0000 Subject: [PATCH 06/17] Pre-commit fix --- socketcan_adapter/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/socketcan_adapter/README.md b/socketcan_adapter/README.md index 7ff2800..183b061 100644 --- a/socketcan_adapter/README.md +++ b/socketcan_adapter/README.md @@ -131,7 +131,6 @@ colcon test --packages-select socketcan_adapter Note: Hardware tests require `CAN_AVAILABLE=1` environment variable and a functioning CAN interface. - ### Creating Virtual CAN Interface For testing without hardware: From 8149ef1014c4228138c8c4f317b05cb2ef0c9ab8 Mon Sep 17 00:00:00 2001 From: Zeerek Date: Fri, 29 Aug 2025 19:23:49 +0000 Subject: [PATCH 07/17] Add basic contribution doc --- CONTRIBUTING.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6f63de9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,13 @@ +Any contribution that you make to this repository will +be under the Apache 2 License, as dictated by that +[license](http://www.apache.org/licenses/LICENSE-2.0.html): + +~~~ +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. +~~~ From 2aba0075c28f354c4df61934a45ce8fe952a5432 Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Sat, 30 Aug 2025 03:27:54 +0000 Subject: [PATCH 08/17] Updating to include launch when installed, fixing launch file for socketcan bridge and update cmakelists for adapter to use Ubuntu jammy instead of ROS version --- socketcan_adapter/CMakeLists.txt | 27 ++++++++++++------- socketcan_adapter_ros/CMakeLists.txt | 1 + .../launch/socketcan_bridge_launch.py | 3 ++- 3 files changed, 21 insertions(+), 10 deletions(-) rename {socketcan_adapter => socketcan_adapter_ros}/launch/socketcan_bridge_launch.py (98%) diff --git a/socketcan_adapter/CMakeLists.txt b/socketcan_adapter/CMakeLists.txt index 75051ed..674c2fd 100644 --- a/socketcan_adapter/CMakeLists.txt +++ b/socketcan_adapter/CMakeLists.txt @@ -36,14 +36,23 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${ASAN_FLAGS}") endif() -# Distro detection (override with -BUILD_HUMBLE=ON/OFF) -if(NOT DEFINED BUILD_HUMBLE) - if(DEFINED ENV{ROS_DISTRO} AND "$ENV{ROS_DISTRO}" STREQUAL "humble") - set(BUILD_HUMBLE TRUE) - message(STATUS "ROS_DISTRO=humble -> using Catch2 v2") - else() - set(BUILD_HUMBLE FALSE) - message(STATUS "ROS_DISTRO>humble -> Catch2 v3 (Jazzy/Rolling)") +# Ubuntu detection (override with -DBUILD_JAMMY=ON/OFF) +if(NOT DEFINED BUILD_JAMMY) + set(BUILD_JAMMY OFF) + if(EXISTS "/etc/os-release") + file(READ "/etc/os-release" _OS_RELEASE) + string(REGEX MATCH "VERSION_CODENAME=([^\n\r]+)" _match "${_OS_RELEASE}") + if(CMAKE_MATCH_1) + set(_UBUNTU_CODENAME "${CMAKE_MATCH_1}") + string(TOLOWER "${_UBUNTU_CODENAME}" _UBUNTU_CODENAME) + if(_UBUNTU_CODENAME STREQUAL "jammy") + set(BUILD_JAMMY ON) + message(STATUS "Ubuntu=jammy (22.04) -> Catch2 v2") + else() + set(BUILD_JAMMY OFF) + message(STATUS "Ubuntu codename='${_UBUNTU_CODENAME}' -> defaulting to Catch2 v3") + endif() + endif() endif() endif() @@ -78,7 +87,7 @@ install(EXPORT ${PROJECT_NAME}_TARGETS if(BUILD_TESTING) include(CTest) # Find correct Catch2 major version per distro - if(BUILD_HUMBLE) + if(BUILD_JAMMY) find_package(Catch2 2 REQUIRED) else() find_package(Catch2 3 REQUIRED) diff --git a/socketcan_adapter_ros/CMakeLists.txt b/socketcan_adapter_ros/CMakeLists.txt index 20f70f6..c5fdd8d 100644 --- a/socketcan_adapter_ros/CMakeLists.txt +++ b/socketcan_adapter_ros/CMakeLists.txt @@ -81,6 +81,7 @@ target_link_libraries(socketcan_bridge PUBLIC socketcan_adapter_ros) # Installs install(DIRECTORY include/ DESTINATION include) +install(DIRECTORY launch/ DESTINATION share/${PROJECT_NAME}/launch) install(TARGETS socketcan_adapter_ros EXPORT ${PROJECT_NAME}_TARGETS ARCHIVE DESTINATION lib diff --git a/socketcan_adapter/launch/socketcan_bridge_launch.py b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py similarity index 98% rename from socketcan_adapter/launch/socketcan_bridge_launch.py rename to socketcan_adapter_ros/launch/socketcan_bridge_launch.py index b2a7c64..001518d 100644 --- a/socketcan_adapter/launch/socketcan_bridge_launch.py +++ b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py @@ -48,9 +48,10 @@ def generate_launch_description(): join_filters_arg = DeclareLaunchArgument('join_filters', default_value='false') socketcan_bridge_node = LifecycleNode( - package='socketcan_adapter', + package='socketcan_adapter_ros', executable='socketcan_bridge', name='socketcan_bridge', + namespace='', parameters=[ { 'can_interface': LaunchConfiguration('can_interface'), From 62c109e30b856b62512dfb83d23411c19a7f09f1 Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Sat, 30 Aug 2025 03:47:09 +0000 Subject: [PATCH 09/17] Updating to try to fix bad topic --- socketcan_adapter_ros/launch/socketcan_bridge_launch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/socketcan_adapter_ros/launch/socketcan_bridge_launch.py b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py index 001518d..a0d408d 100644 --- a/socketcan_adapter_ros/launch/socketcan_bridge_launch.py +++ b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py @@ -44,7 +44,7 @@ def generate_launch_description(): # Define args can_interface_arg = DeclareLaunchArgument('can_interface', default_value='can0') can_error_mask_arg = DeclareLaunchArgument('can_error_mask', default_value='0x1FFFFFFF') - can_filter_list_arg = DeclareLaunchArgument('can_filter_list', default_value=[]) + can_filter_list_arg = DeclareLaunchArgument('can_filter_list', default_value='[]') join_filters_arg = DeclareLaunchArgument('join_filters', default_value='false') socketcan_bridge_node = LifecycleNode( From ef4a29956e09d18ed469f3892abed87a4928f013 Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Sat, 30 Aug 2025 04:16:53 +0000 Subject: [PATCH 10/17] Empty list is broken, fix it by force passing it in, although it is not exactly the best practice --- socketcan_adapter_ros/launch/socketcan_bridge_launch.py | 5 +++-- socketcan_adapter_ros/src/socketcan_bridge_node.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/socketcan_adapter_ros/launch/socketcan_bridge_launch.py b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py index a0d408d..e41ba77 100644 --- a/socketcan_adapter_ros/launch/socketcan_bridge_launch.py +++ b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py @@ -38,13 +38,14 @@ from launch_ros.event_handlers import OnStateTransition from launch_ros.events.lifecycle import ChangeState from lifecycle_msgs.msg import Transition +from launch_ros.parameter_descriptions import ParameterValue def generate_launch_description(): # Define args can_interface_arg = DeclareLaunchArgument('can_interface', default_value='can0') can_error_mask_arg = DeclareLaunchArgument('can_error_mask', default_value='0x1FFFFFFF') - can_filter_list_arg = DeclareLaunchArgument('can_filter_list', default_value='[]') + can_filter_list_arg = DeclareLaunchArgument('can_filter_list', default_value="['']") join_filters_arg = DeclareLaunchArgument('join_filters', default_value='false') socketcan_bridge_node = LifecycleNode( @@ -56,7 +57,7 @@ def generate_launch_description(): { 'can_interface': LaunchConfiguration('can_interface'), 'can_error_mask': LaunchConfiguration('can_error_mask'), - 'can_filter_list': LaunchConfiguration('can_filter_list'), + 'can_filter_list': ParameterValue(LaunchConfiguration('can_filter_list'), value_type=list[str]), 'join_filters': LaunchConfiguration('join_filters'), } ], diff --git a/socketcan_adapter_ros/src/socketcan_bridge_node.cpp b/socketcan_adapter_ros/src/socketcan_bridge_node.cpp index e770ac6..558fa3f 100644 --- a/socketcan_adapter_ros/src/socketcan_bridge_node.cpp +++ b/socketcan_adapter_ros/src/socketcan_bridge_node.cpp @@ -32,7 +32,7 @@ SocketcanBridgeNode::SocketcanBridgeNode(const rclcpp::NodeOptions & options) { declare_parameter("can_interface", std::string("can0")); declare_parameter("can_error_mask", static_cast(CAN_ERR_MASK)); - declare_parameter("can_filter_list", {}); // vector of strings + declare_parameter("can_filter_list", std::vector{}); // vector of strings declare_parameter("join_filters", false); declare_parameter("receive_timeout_s", SOCKET_RECEIVE_TIMEOUT_S.count()); } From 25690c447376a2aac689dfb64e1fc3e694d31f80 Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Sat, 30 Aug 2025 04:17:11 +0000 Subject: [PATCH 11/17] pre-commit --- socketcan_adapter_ros/launch/socketcan_bridge_launch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/socketcan_adapter_ros/launch/socketcan_bridge_launch.py b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py index e41ba77..0379b00 100644 --- a/socketcan_adapter_ros/launch/socketcan_bridge_launch.py +++ b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py @@ -37,8 +37,8 @@ from launch_ros.actions import LifecycleNode from launch_ros.event_handlers import OnStateTransition from launch_ros.events.lifecycle import ChangeState -from lifecycle_msgs.msg import Transition from launch_ros.parameter_descriptions import ParameterValue +from lifecycle_msgs.msg import Transition def generate_launch_description(): From a5c1a790f3211ff579e70804b450048fe49a5049 Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Sat, 30 Aug 2025 04:36:29 +0000 Subject: [PATCH 12/17] Trying to fix up poll and everything --- socketcan_adapter/src/socketcan_adapter.cpp | 9 ++++++--- socketcan_adapter_ros/src/socketcan_bridge_node.cpp | 3 +++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/socketcan_adapter/src/socketcan_adapter.cpp b/socketcan_adapter/src/socketcan_adapter.cpp index b7608d8..ca13b5e 100644 --- a/socketcan_adapter/src/socketcan_adapter.cpp +++ b/socketcan_adapter/src/socketcan_adapter.cpp @@ -126,10 +126,11 @@ std::optional SocketcanAdapter::receive fds[0].fd = socket_file_descriptor_; fds[0].events = POLLIN | POLLERR; + auto poll_timeout_ms = std::chrono::duration_cast(receive_timeout_s_).count(); + /// TODO: We don't need to call duration cast every time we run this, we should store milliseconds instead /// https://gitlab.com/polymathrobotics/polymath_core/-/issues/8 - int return_value = poll( - fds, NUM_SOCKETS_IN_ADAPTER, std::chrono::duration_cast(receive_timeout_s_).count()); + int return_value = poll(fds, NUM_SOCKETS_IN_ADAPTER, poll_timeout_ms); socket_error_string_t error_string; @@ -139,7 +140,9 @@ std::optional SocketcanAdapter::receive } if (return_value == 0) { - return std::optional("poll timed out with no data"); + socket_error_string_t err_string = + socket_error_string_t("poll timed out with no data with timeout") + std::to_string(poll_timeout_ms); + return std::optional(err_string); } if (fds[0].revents & POLLERR) { diff --git a/socketcan_adapter_ros/src/socketcan_bridge_node.cpp b/socketcan_adapter_ros/src/socketcan_bridge_node.cpp index 558fa3f..1f718b8 100644 --- a/socketcan_adapter_ros/src/socketcan_bridge_node.cpp +++ b/socketcan_adapter_ros/src/socketcan_bridge_node.cpp @@ -101,6 +101,8 @@ SocketcanBridgeNode::rclcpp_lifecycle_callback_return SocketcanBridgeNode::on_co socketcan_adapter_->setOnErrorCallback( std::bind(&SocketcanBridgeNode::socketErrorCallback, this, std::placeholders::_1)); + RCLCPP_INFO(get_logger(), "Finished configuration!"); + return LifecycleNode::on_configure(state); } @@ -117,6 +119,7 @@ SocketcanBridgeNode::rclcpp_lifecycle_callback_return SocketcanBridgeNode::on_ac return rclcpp_lifecycle_callback_return::FAILURE; } + RCLCPP_INFO(get_logger(), "Finished activation!"); return LifecycleNode::on_activate(state); } From f1f4ecea6e3f6d118db2c43147f3d09f2a039e69 Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Sat, 30 Aug 2025 04:43:16 +0000 Subject: [PATCH 13/17] Increase default receive timeout --- socketcan_adapter_ros/launch/socketcan_bridge_launch.py | 3 +++ socketcan_adapter_ros/src/socketcan_bridge.cpp | 7 ------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/socketcan_adapter_ros/launch/socketcan_bridge_launch.py b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py index 0379b00..9d6e364 100644 --- a/socketcan_adapter_ros/launch/socketcan_bridge_launch.py +++ b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py @@ -47,6 +47,7 @@ def generate_launch_description(): can_error_mask_arg = DeclareLaunchArgument('can_error_mask', default_value='0x1FFFFFFF') can_filter_list_arg = DeclareLaunchArgument('can_filter_list', default_value="['']") join_filters_arg = DeclareLaunchArgument('join_filters', default_value='false') + receive_timeout_arg = DeclareLaunchArgument('receive_timeout_s', default_value=1) socketcan_bridge_node = LifecycleNode( package='socketcan_adapter_ros', @@ -59,6 +60,7 @@ def generate_launch_description(): 'can_error_mask': LaunchConfiguration('can_error_mask'), 'can_filter_list': ParameterValue(LaunchConfiguration('can_filter_list'), value_type=list[str]), 'join_filters': LaunchConfiguration('join_filters'), + 'receive_timeout_s': LaunchConfiguration('receive_timeout_s'), } ], output='screen', @@ -101,6 +103,7 @@ def generate_launch_description(): can_error_mask_arg, can_filter_list_arg, join_filters_arg, + receive_timeout_arg, DeclareLaunchArgument('auto_configure', default_value='true'), DeclareLaunchArgument('auto_activate', default_value='true'), socketcan_bridge_node, diff --git a/socketcan_adapter_ros/src/socketcan_bridge.cpp b/socketcan_adapter_ros/src/socketcan_bridge.cpp index 9d9cfba..d1bbc53 100644 --- a/socketcan_adapter_ros/src/socketcan_bridge.cpp +++ b/socketcan_adapter_ros/src/socketcan_bridge.cpp @@ -29,15 +29,8 @@ int main(int argc, char ** argv) executor.add_node(node->get_node_base_interface()); - node->configure(); - node->activate(); - executor.spin(); - node->deactivate(); - node->cleanup(); - node->shutdown(); - rclcpp::shutdown(); return 0; From 1df95c4ea86519b7a0d45063e0f76e09d9cf8d1f Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Sat, 30 Aug 2025 04:44:11 +0000 Subject: [PATCH 14/17] Increase default timeout using string --- socketcan_adapter_ros/launch/socketcan_bridge_launch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/socketcan_adapter_ros/launch/socketcan_bridge_launch.py b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py index 9d6e364..fb7cf16 100644 --- a/socketcan_adapter_ros/launch/socketcan_bridge_launch.py +++ b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py @@ -47,7 +47,7 @@ def generate_launch_description(): can_error_mask_arg = DeclareLaunchArgument('can_error_mask', default_value='0x1FFFFFFF') can_filter_list_arg = DeclareLaunchArgument('can_filter_list', default_value="['']") join_filters_arg = DeclareLaunchArgument('join_filters', default_value='false') - receive_timeout_arg = DeclareLaunchArgument('receive_timeout_s', default_value=1) + receive_timeout_arg = DeclareLaunchArgument('receive_timeout_s', default_value='1.0') socketcan_bridge_node = LifecycleNode( package='socketcan_adapter_ros', From 6495e90851b9bda897f4836b64a857a0cc21268f Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Sat, 30 Aug 2025 05:41:03 +0000 Subject: [PATCH 15/17] Add default filters to keep CAN flowing --- socketcan_adapter_ros/launch/socketcan_bridge_launch.py | 2 +- socketcan_adapter_ros/src/socketcan_bridge_node.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/socketcan_adapter_ros/launch/socketcan_bridge_launch.py b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py index fb7cf16..16586a1 100644 --- a/socketcan_adapter_ros/launch/socketcan_bridge_launch.py +++ b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py @@ -45,7 +45,7 @@ def generate_launch_description(): # Define args can_interface_arg = DeclareLaunchArgument('can_interface', default_value='can0') can_error_mask_arg = DeclareLaunchArgument('can_error_mask', default_value='0x1FFFFFFF') - can_filter_list_arg = DeclareLaunchArgument('can_filter_list', default_value="['']") + can_filter_list_arg = DeclareLaunchArgument('can_filter_list', default_value="['0:0']") join_filters_arg = DeclareLaunchArgument('join_filters', default_value='false') receive_timeout_arg = DeclareLaunchArgument('receive_timeout_s', default_value='1.0') diff --git a/socketcan_adapter_ros/src/socketcan_bridge_node.cpp b/socketcan_adapter_ros/src/socketcan_bridge_node.cpp index 1f718b8..ccc30b6 100644 --- a/socketcan_adapter_ros/src/socketcan_bridge_node.cpp +++ b/socketcan_adapter_ros/src/socketcan_bridge_node.cpp @@ -32,7 +32,7 @@ SocketcanBridgeNode::SocketcanBridgeNode(const rclcpp::NodeOptions & options) { declare_parameter("can_interface", std::string("can0")); declare_parameter("can_error_mask", static_cast(CAN_ERR_MASK)); - declare_parameter("can_filter_list", std::vector{}); // vector of strings + declare_parameter("can_filter_list", std::vector{'0:0'}); // vector of strings declare_parameter("join_filters", false); declare_parameter("receive_timeout_s", SOCKET_RECEIVE_TIMEOUT_S.count()); } From f01afef986d62da0fe66fb2f47a06e40e8e1a827 Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Sat, 30 Aug 2025 05:42:07 +0000 Subject: [PATCH 16/17] Vector of strings need quotes --- socketcan_adapter_ros/src/socketcan_bridge_node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/socketcan_adapter_ros/src/socketcan_bridge_node.cpp b/socketcan_adapter_ros/src/socketcan_bridge_node.cpp index ccc30b6..e8490f1 100644 --- a/socketcan_adapter_ros/src/socketcan_bridge_node.cpp +++ b/socketcan_adapter_ros/src/socketcan_bridge_node.cpp @@ -32,7 +32,7 @@ SocketcanBridgeNode::SocketcanBridgeNode(const rclcpp::NodeOptions & options) { declare_parameter("can_interface", std::string("can0")); declare_parameter("can_error_mask", static_cast(CAN_ERR_MASK)); - declare_parameter("can_filter_list", std::vector{'0:0'}); // vector of strings + declare_parameter("can_filter_list", std::vector{"0:0"}); // vector of strings declare_parameter("join_filters", false); declare_parameter("receive_timeout_s", SOCKET_RECEIVE_TIMEOUT_S.count()); } From fac7b5bf5e80906f633a015489aac127e2faf418 Mon Sep 17 00:00:00 2001 From: Zeerek Ahmad Date: Sat, 30 Aug 2025 05:44:28 +0000 Subject: [PATCH 17/17] Default filters to everything allowed. Add some comments --- socketcan_adapter_ros/launch/socketcan_bridge_launch.py | 1 + socketcan_adapter_ros/src/socketcan_bridge_node.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/socketcan_adapter_ros/launch/socketcan_bridge_launch.py b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py index 16586a1..bb0005a 100644 --- a/socketcan_adapter_ros/launch/socketcan_bridge_launch.py +++ b/socketcan_adapter_ros/launch/socketcan_bridge_launch.py @@ -45,6 +45,7 @@ def generate_launch_description(): # Define args can_interface_arg = DeclareLaunchArgument('can_interface', default_value='can0') can_error_mask_arg = DeclareLaunchArgument('can_error_mask', default_value='0x1FFFFFFF') + # Default filter:mask [0:0] means ALL traffic is allowed can_filter_list_arg = DeclareLaunchArgument('can_filter_list', default_value="['0:0']") join_filters_arg = DeclareLaunchArgument('join_filters', default_value='false') receive_timeout_arg = DeclareLaunchArgument('receive_timeout_s', default_value='1.0') diff --git a/socketcan_adapter_ros/src/socketcan_bridge_node.cpp b/socketcan_adapter_ros/src/socketcan_bridge_node.cpp index e8490f1..cce4b29 100644 --- a/socketcan_adapter_ros/src/socketcan_bridge_node.cpp +++ b/socketcan_adapter_ros/src/socketcan_bridge_node.cpp @@ -32,7 +32,8 @@ SocketcanBridgeNode::SocketcanBridgeNode(const rclcpp::NodeOptions & options) { declare_parameter("can_interface", std::string("can0")); declare_parameter("can_error_mask", static_cast(CAN_ERR_MASK)); - declare_parameter("can_filter_list", std::vector{"0:0"}); // vector of strings + // Vector of strings, default 0:0 means ALL traffic allowed + declare_parameter("can_filter_list", std::vector{"0:0"}); declare_parameter("join_filters", false); declare_parameter("receive_timeout_s", SOCKET_RECEIVE_TIMEOUT_S.count()); }