Skip to content

Commit f6fb1bb

Browse files
authored
Split socketcan adapter and socketcan adapter ros (#3)
* Split socketcan adapter and socketcan adapter ros * Update readmes via guided AI (prior to cleanup) and pre-commit * Cleanup top level readme.md * Update README.md Remove emojis * Further clean up readmes * Pre-commit fix * Add basic contribution doc * 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 * Updating to try to fix bad topic * Empty list is broken, fix it by force passing it in, although it is not exactly the best practice * pre-commit * Trying to fix up poll and everything * Increase default receive timeout * Increase default timeout using string * Add default filters to keep CAN flowing * Vector of strings need quotes * Default filters to everything allowed. Add some comments
1 parent 443d5af commit f6fb1bb

File tree

18 files changed

+489
-151
lines changed

18 files changed

+489
-151
lines changed

CONTRIBUTING.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Any contribution that you make to this repository will
2+
be under the Apache 2 License, as dictated by that
3+
[license](http://www.apache.org/licenses/LICENSE-2.0.html):
4+
5+
~~~
6+
5. Submission of Contributions. Unless You explicitly state otherwise,
7+
any Contribution intentionally submitted for inclusion in the Work
8+
by You to the Licensor shall be under the terms and conditions of
9+
this License, without any additional terms or conditions.
10+
Notwithstanding the above, nothing herein shall supersede or modify
11+
the terms of any separate license agreement you may have executed
12+
with Licensor regarding such Contributions.
13+
~~~

README.md

Lines changed: 69 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,97 @@
1-
# socketcan_adapter
2-
Socketcan Driver Library for Linux based PCs and ROS2 nodes
1+
# SocketCAN Adapter
32

4-
# Build
5-
Socketcan adapter can be built with the ros2 ament toolchain. All requirements can be installed via rosdep
3+
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.
64

7-
Install the dependencies!
5+
## Architecture
6+
7+
This package is split into two complementary components:
8+
9+
### [socketcan_adapter](./socketcan_adapter/README.md)
10+
Pure C++ SocketCAN library with no ROS dependencies.
11+
- Core SocketCAN functionality
12+
- Thread-safe operations
13+
- Callback-based asynchronous processing
14+
- Configurable filters and error handling
15+
- Can be used in non-ROS projects
16+
17+
### [socketcan_adapter_ros](./socketcan_adapter_ros/README.md)
18+
ROS2 wrapper providing nodes and launch files.
19+
- ROS2 lifecycle node
20+
- Integration with `can_msgs`
21+
- Launch files with parameter support
22+
- Depends on the core `socketcan_adapter` library
23+
24+
## Quick Start
25+
26+
### Build Both Packages
827

928
```bash
10-
rosdep install -i -y --from-paths socketcan_adapter
29+
# Install dependencies
30+
rosdep install -i -y --from-paths .
31+
32+
# Build everything
33+
colcon build --packages-up-to socketcan_adapter_ros
1134
```
1235

13-
Build it!
36+
### Launch ROS2 CAN Bridge
1437

1538
```bash
16-
colcon build --packages-up-to socketcan_adapter
39+
ros2 launch socketcan_adapter_ros socketcan_bridge_launch.py
1740
```
1841

19-
# Library
20-
## Classes of Note
21-
### CanFrame
22-
`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.
42+
### Use Core Library in C++
2343

24-
Example highlights:
44+
```c++
45+
#include "socketcan_adapter/socketcan_adapter.hpp"
2546

26-
- Flexible constructors for `can_frame` struct and raw data inputs.
27-
- Functions to modify frame type, ID type (standard/extended), and length.
28-
- Helper methods to access CAN frame data, ID, and timestamp.
47+
using namespace polymath::socketcan;
2948

30-
Does not implement CanFD yet.
49+
SocketcanAdapter adapter("can0");
50+
adapter.openSocket();
51+
// ... see socketcan_adapter README for full example
52+
```
3153
32-
### SocketcanAdapter
33-
`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.
54+
## Requirements
3455
35-
Key features:
56+
### System Requirements
57+
- Linux with SocketCAN support
58+
- C++17 compatible compiler
59+
- CMake 3.8+
3660
37-
- Configurable receive timeout and threading for reception.
38-
- `setFilters` and setErrorMaskOverwrite to apply CAN filters and error masks.
39-
- A callback-based system for handling received frames and errors asynchronously.
40-
- Supports multiple send and receive methods, including `std::shared_ptr` for efficient memory management.
41-
- 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.
61+
### ROS2 Requirements (for ROS package only)
62+
- ROS2 Humble or later
63+
- can_msgs package
4264
43-
## Sample Usage
65+
## Testing
4466
45-
```c++
46-
#include "socketcan_adapter/socketcan_adapter.hpp"
47-
#include "socketcan_adapter/can_frame.hpp"
48-
#include <iostream>
49-
#include <thread>
50-
#include <vector>
67+
### Core Library Tests
5168
52-
using namespace polymath::socketcan;
69+
```bash
70+
colcon test --packages-select socketcan_adapter
71+
```
5372

54-
int main() {
55-
// Initialize SocketcanAdapter with the CAN interface name (e.g., "can0")
56-
SocketcanAdapter adapter("can0");
57-
58-
// Open the CAN socket
59-
if (!adapter.openSocket()) {
60-
std::cerr << "Failed to open CAN socket!" << std::endl;
61-
return -1;
62-
}
63-
64-
// Step 1: Set up a filter to allow only messages with ID 0x123
65-
std::vector<struct can_filter> filters = {{0x123, CAN_SFF_MASK}};
66-
if (auto error = adapter.setFilters(filters)) {
67-
std::cerr << "Error setting filters: " << *error << std::endl;
68-
return -1;
69-
}
70-
71-
// Step 2: Set up a callback function to handle received CAN frames
72-
adapter.setOnReceiveCallback([](std::unique_ptr<const CanFrame> frame) {
73-
std::cout << "Received CAN frame with ID: " << std::hex << frame->get_id() << std::endl;
74-
auto data = frame->get_data();
75-
std::cout << "Data: ";
76-
for (const auto& byte : data) {
77-
std::cout << std::hex << static_cast<int>(byte) << " ";
78-
}
79-
std::cout << std::endl;
80-
});
81-
82-
// Step 3: Start the reception thread
83-
if (!adapter.startReceptionThread()) {
84-
std::cerr << "Failed to start reception thread!" << std::endl;
85-
adapter.closeSocket();
86-
return -1;
87-
}
88-
89-
// Step 4: Prepare a CAN frame to send
90-
canid_t raw_id = 0x123;
91-
std::array<unsigned char, CAN_MAX_DLC> data = {0x11, 0x22, 0x33, 0x44};
92-
uint64_t timestamp = 0; // Placeholder timestamp
93-
CanFrame frame(raw_id, data, timestamp);
94-
95-
// Step 5: Send the CAN frame
96-
if (auto error = adapter.send(frame)) {
97-
std::cerr << "Failed to send CAN frame: " << *error << std::endl;
98-
} else {
99-
std::cout << "Sent CAN frame with ID: " << std::hex << raw_id << std::endl;
100-
}
101-
102-
// Keep the application running for 10 seconds to allow for frame reception
103-
std::this_thread::sleep_for(std::chrono::seconds(10));
104-
105-
// Step 5: Clean up - close the socket and stop the reception thread
106-
adapter.joinReceptionThread();
107-
adapter.closeSocket();
108-
109-
return 0;
110-
}
73+
### Hardware Tests
74+
Set `CAN_AVAILABLE=1` to enable hardware-dependent tests:
11175

76+
```bash
77+
CAN_AVAILABLE=1 colcon test --packages-select socketcan_adapter
11278
```
11379

114-
# ROS2 Node
115-
To make usage even easier, this package comes with a ROS2 node with default settings!
80+
## Virtual CAN Setup
11681

117-
## Launch
82+
For testing without hardware:
11883

11984
```bash
120-
ros2 launch socketcan_adapter socketcan_bridge_launch.py
85+
sudo modprobe vcan
86+
sudo ip link add dev vcan0 type vcan
87+
sudo ip link set up vcan0
12188
```
12289

123-
launch args:
124-
- `can_interface`: can interface to connect to (default: 0)
125-
- `can_error_mask`: can error mask (default: 0x1FFFFFFF aka everything allowed)
126-
- `can_filter_list`: can filters (default: [])
127-
- `join_filters`: use joining logic for filters (default: false)
128-
- `auto_configure`: automatically configure the lifecycle node
129-
- `auto_activate`: automatically activate the lifecycle node post configuration
90+
## License
91+
92+
Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for the full license text.
93+
94+
## Authors & Maintainers
95+
96+
- **Zeerek Ahmad** - Original author - zeerekahmad@hotmail.com
97+
- **Polymath Robotics Engineering Team** - Maintainers - engineering@polymathrobotics.com

CMakeLists.txt renamed to socketcan_adapter/CMakeLists.txt

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,27 +36,32 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
3636
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${ASAN_FLAGS}")
3737
endif()
3838

39-
# Distro detection (override with -BUILD_HUMBLE=ON/OFF)
40-
if(NOT DEFINED BUILD_HUMBLE)
41-
if(DEFINED ENV{ROS_DISTRO} AND "$ENV{ROS_DISTRO}" STREQUAL "humble")
42-
set(BUILD_HUMBLE TRUE)
43-
message(STATUS "ROS_DISTRO=humble -> using Catch2 v2")
44-
else()
45-
set(BUILD_HUMBLE FALSE)
46-
message(STATUS "ROS_DISTRO>humble -> Catch2 v3 (Jazzy/Rolling)")
39+
# Ubuntu detection (override with -DBUILD_JAMMY=ON/OFF)
40+
if(NOT DEFINED BUILD_JAMMY)
41+
set(BUILD_JAMMY OFF)
42+
if(EXISTS "/etc/os-release")
43+
file(READ "/etc/os-release" _OS_RELEASE)
44+
string(REGEX MATCH "VERSION_CODENAME=([^\n\r]+)" _match "${_OS_RELEASE}")
45+
if(CMAKE_MATCH_1)
46+
set(_UBUNTU_CODENAME "${CMAKE_MATCH_1}")
47+
string(TOLOWER "${_UBUNTU_CODENAME}" _UBUNTU_CODENAME)
48+
if(_UBUNTU_CODENAME STREQUAL "jammy")
49+
set(BUILD_JAMMY ON)
50+
message(STATUS "Ubuntu=jammy (22.04) -> Catch2 v2")
51+
else()
52+
set(BUILD_JAMMY OFF)
53+
message(STATUS "Ubuntu codename='${_UBUNTU_CODENAME}' -> defaulting to Catch2 v3")
54+
endif()
55+
endif()
4756
endif()
4857
endif()
4958

5059
# Dependencies
5160
find_package(ament_cmake REQUIRED)
52-
find_package(rclcpp REQUIRED)
53-
find_package(rclcpp_lifecycle REQUIRED)
54-
find_package(can_msgs REQUIRED)
5561

5662
# Primary library
5763
add_library(socketcan_adapter SHARED
5864
src/socketcan_adapter.cpp
59-
src/socketcan_bridge_node.cpp
6065
src/can_frame.cpp
6166
)
6267
target_include_directories(socketcan_adapter PUBLIC
@@ -65,20 +70,6 @@ target_include_directories(socketcan_adapter PUBLIC
6570
)
6671
target_compile_definitions(socketcan_adapter PRIVATE "SOCKETCAN_ADAPTER_BUILDING_LIBRARY")
6772

68-
# Executable using the library
69-
add_executable(socketcan_bridge src/socketcan_bridge.cpp)
70-
target_include_directories(socketcan_bridge PUBLIC
71-
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
72-
$<INSTALL_INTERFACE:include>
73-
)
74-
75-
target_link_libraries(socketcan_adapter PUBLIC
76-
${can_msgs_TARGETS}
77-
rclcpp::rclcpp
78-
rclcpp_lifecycle::rclcpp_lifecycle
79-
)
80-
target_link_libraries(socketcan_bridge PUBLIC socketcan_adapter)
81-
8273
# Installs
8374
install(DIRECTORY include/ DESTINATION include)
8475
install(TARGETS socketcan_adapter
@@ -87,7 +78,6 @@ install(TARGETS socketcan_adapter
8778
LIBRARY DESTINATION lib
8879
RUNTIME DESTINATION bin
8980
)
90-
install(TARGETS socketcan_bridge DESTINATION lib/${PROJECT_NAME})
9181
install(EXPORT ${PROJECT_NAME}_TARGETS
9282
NAMESPACE ${PROJECT_NAME}::
9383
DESTINATION share/${PROJECT_NAME}/cmake
@@ -97,7 +87,7 @@ install(EXPORT ${PROJECT_NAME}_TARGETS
9787
if(BUILD_TESTING)
9888
include(CTest)
9989
# Find correct Catch2 major version per distro
100-
if(BUILD_HUMBLE)
90+
if(BUILD_JAMMY)
10191
find_package(Catch2 2 REQUIRED)
10292
else()
10393
find_package(Catch2 3 REQUIRED)

0 commit comments

Comments
 (0)