|
1 | 1 | # socketcan_adapter
|
2 | 2 | Socketcan Driver Library for Linux based PCs and ROS2 nodes
|
| 3 | + |
| 4 | +# Build |
| 5 | +Socketcan adapter can be built with the ros2 ament toolchain. All requirements can be installed via rosdep |
| 6 | + |
| 7 | +Install the dependencies! |
| 8 | +```bash |
| 9 | +rosdep install -i -y --from-paths socketcan_adapter |
| 10 | +``` |
| 11 | + |
| 12 | +Build it! |
| 13 | +```bash |
| 14 | +colcon build --packages-up-to socketcan_adapter |
| 15 | +``` |
| 16 | + |
| 17 | +# Library |
| 18 | +## Classes of Note |
| 19 | +### CanFrame |
| 20 | +`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. |
| 21 | + |
| 22 | +Example highlights: |
| 23 | + |
| 24 | +- Flexible constructors for `can_frame` struct and raw data inputs. |
| 25 | +- Functions to modify frame type, ID type (standard/extended), and length. |
| 26 | +- Helper methods to access CAN frame data, ID, and timestamp. |
| 27 | + |
| 28 | +Does not implement CanFD yet. |
| 29 | + |
| 30 | +### SocketcanAdapter |
| 31 | +`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. |
| 32 | + |
| 33 | +Key features: |
| 34 | + |
| 35 | +- Configurable receive timeout and threading for reception. |
| 36 | +- `setFilters` and setErrorMaskOverwrite to apply CAN filters and error masks. |
| 37 | +- A callback-based system for handling received frames and errors asynchronously. |
| 38 | +- Supports multiple send and receive methods, including `std::shared_ptr` for efficient memory management. |
| 39 | +- 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. |
| 40 | + |
| 41 | +## Sample Usage |
| 42 | + |
| 43 | +```c++ |
| 44 | +#include "socketcan_adapter/socketcan_adapter.hpp" |
| 45 | +#include "socketcan_adapter/can_frame.hpp" |
| 46 | +#include <iostream> |
| 47 | +#include <thread> |
| 48 | +#include <vector> |
| 49 | + |
| 50 | +using namespace polymath::socketcan; |
| 51 | + |
| 52 | +int main() { |
| 53 | + // Initialize SocketcanAdapter with the CAN interface name (e.g., "can0") |
| 54 | + SocketcanAdapter adapter("can0"); |
| 55 | + |
| 56 | + // Open the CAN socket |
| 57 | + if (!adapter.openSocket()) { |
| 58 | + std::cerr << "Failed to open CAN socket!" << std::endl; |
| 59 | + return -1; |
| 60 | + } |
| 61 | + |
| 62 | + // Step 1: Set up a filter to allow only messages with ID 0x123 |
| 63 | + std::vector<struct can_filter> filters = {{0x123, CAN_SFF_MASK}}; |
| 64 | + if (auto error = adapter.setFilters(filters)) { |
| 65 | + std::cerr << "Error setting filters: " << *error << std::endl; |
| 66 | + return -1; |
| 67 | + } |
| 68 | + |
| 69 | + // Step 2: Set up a callback function to handle received CAN frames |
| 70 | + adapter.setOnReceiveCallback([](std::unique_ptr<const CanFrame> frame) { |
| 71 | + std::cout << "Received CAN frame with ID: " << std::hex << frame->get_id() << std::endl; |
| 72 | + auto data = frame->get_data(); |
| 73 | + std::cout << "Data: "; |
| 74 | + for (const auto& byte : data) { |
| 75 | + std::cout << std::hex << static_cast<int>(byte) << " "; |
| 76 | + } |
| 77 | + std::cout << std::endl; |
| 78 | + }); |
| 79 | + |
| 80 | + // Step 3: Start the reception thread |
| 81 | + if (!adapter.startReceptionThread()) { |
| 82 | + std::cerr << "Failed to start reception thread!" << std::endl; |
| 83 | + adapter.closeSocket(); |
| 84 | + return -1; |
| 85 | + } |
| 86 | + |
| 87 | + // Step 4: Prepare a CAN frame to send |
| 88 | + canid_t raw_id = 0x123; |
| 89 | + std::array<unsigned char, CAN_MAX_DLC> data = {0x11, 0x22, 0x33, 0x44}; |
| 90 | + uint64_t timestamp = 0; // Placeholder timestamp |
| 91 | + CanFrame frame(raw_id, data, timestamp); |
| 92 | + |
| 93 | + // Step 5: Send the CAN frame |
| 94 | + if (auto error = adapter.send(frame)) { |
| 95 | + std::cerr << "Failed to send CAN frame: " << *error << std::endl; |
| 96 | + } else { |
| 97 | + std::cout << "Sent CAN frame with ID: " << std::hex << raw_id << std::endl; |
| 98 | + } |
| 99 | + |
| 100 | + // Keep the application running for 10 seconds to allow for frame reception |
| 101 | + std::this_thread::sleep_for(std::chrono::seconds(10)); |
| 102 | + |
| 103 | + // Step 5: Clean up - close the socket and stop the reception thread |
| 104 | + adapter.joinReceptionThread(); |
| 105 | + adapter.closeSocket(); |
| 106 | + |
| 107 | + return 0; |
| 108 | +} |
| 109 | + |
| 110 | +``` |
| 111 | +
|
| 112 | +# ROS2 Node |
| 113 | +To make usage even easier, this package comes with a ROS2 node with default settings! |
| 114 | +
|
| 115 | +## Launch |
| 116 | +```bash |
| 117 | +ros2 launch socketcan_adapter socketcan_bridge_launch.py |
| 118 | +``` |
| 119 | + |
| 120 | +launch args: |
| 121 | +- `can_interface`: can interface to connect to (default: 0) |
| 122 | +- `can_error_mask`: can error mask (default: 0x1FFFFFFF aka everything allowed) |
| 123 | +- `can_filter_list`: can filters (default: []) |
| 124 | +- `join_filters`: use joining logic for filters (default: false) |
| 125 | +- `auto_configure`: automatically configure the lifecycle node |
| 126 | +- `auto_activate`: automatically activate the lifecycle node post configuration |
0 commit comments