PEAK-System® PCAN®-Basic
Controller Area Network (CAN) is one of the widely used Fieldbus protocols in industrial automation. On Linux, applications can talk to a CAN bus over SocketCAN. On Windows, applications talk to a CAN bus using vendor-provided libraries.
Today we are demonstrate how to use a CAN library, PCAN-Basic, from PEAK-System Technik GmbH. In this tutorial, we will show you an example how to begin with a ROS package, integrate with the CAN library, and perform the basic I/O to a CAN Bus.
For more details, visit PEAK-System.
Prerequisite
- You have a machine with
Windows 10
installed. - You have
ROS Melodic Desktop Full
installed. - You have PCAN adapters.
We use
PCAN-miniPCIe
in this tutorial. - You have the CAN adapters connected to a CAN network and all devices are commissioned to work.
- You have a ROS command prompt ready to use.
Step 1: Creating a ROS package
Firstly, you will need a catkin
workspace to begin with.
Assuming you have an empty workspace under c:\can_ws
, now create a new package.
:: change the directory to the source subfolder.
c:\can_ws> cd src
:: create your owned package
c:\can_ws\src> catkin_create_pkg my_pkg
Step 2: Adding PCAN-Basic SDK
The next step is to add PCAN-Basic
library into your package.
This example shows a way to pull and place the library into the correct location by CMake
convention.
Now open and edit the CMakeLists.txt
under src\my_pkg
.
# Decide what architecture for the target
set(TARGET_ARCH "Win32")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(TARGET_ARCH "x64")
endif()
# Create locations to place the PCAN-Basic library
file(MAKE_DIRECTORY
${CMAKE_BINARY_DIR}/installed/pcan-basic/bin
${CMAKE_BINARY_DIR}/installed/pcan-basic/lib
${CMAKE_BINARY_DIR}/installed/pcan-basic/include)
# Pull down the PCAN-Basic library
include(ExternalProject)
ExternalProject_Add(
pcan-basic
URL https://www.peak-system.com/fileadmin/media/files/pcan-basic.zip
URL_MD5 d388e723046e7b2f6bd06489a12a3d96
PREFIX ${CMAKE_BINARY_DIR}/pcan-basic
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory
<SOURCE_DIR>/include ${CMAKE_BINARY_DIR}/installed/pcan-basic/include
COMMAND ${CMAKE_COMMAND} -E copy
<SOURCE_DIR>/${TARGET_ARCH}/PCANBasic.dll ${CMAKE_BINARY_DIR}/installed/pcan-basic/bin
COMMAND ${CMAKE_COMMAND} -E copy
<SOURCE_DIR>/${TARGET_ARCH}/VC_LIB/PCANBasic.lib ${CMAKE_BINARY_DIR}/installed/pcan-basic/lib
LOG_DOWNLOAD ON
LOG_INSTALL ON
)
# Initialize include paths and library paths
set(pcan_LIBRARIES ${CMAKE_BINARY_DIR}/installed/pcan-basic/lib/PCANBasic.lib)
set(pcan_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/installed/pcan-basic/include)
# Remember to install the DLL side-by-side to ROS application
install(FILES
${CMAKE_BINARY_DIR}/installed/pcan-basic/bin/PCANBasic.dll
DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}
)
And now you can build the package and see if everything is set up correctly.
:: Build the workspace
c:\can_ws> catkin_make install
:: Add the install space into the current environment.
c:\can_ws> install\setup.bat
Step 3: Adding Simple CAN Read\Write Loop
Now you have the PCAN-Basic library ready to use in your ROS workspace.
We are going to add a simple node doing the basic read/write loop.
Now you go to the editor, create a file of src/my_pkg/src/my_pkg_node.cpp
under your workspace, and copy & paste the below code:
#include <windows.h>
#include <PCANBasic.h>
#include <exception>
#include <iostream>
#include <ros/ros.h>
#include <ros/callback_queue.h>
#include <ros/console.h>
class PCANLoop
{
public:
PCANLoop()
{
TPCANStatus result = CAN_Initialize(PCAN_PCIBUS1, PCAN_BAUD_500K);
if (result != PCAN_ERROR_OK)
{
throw std::runtime_error("CAN_Initialize failed.");
}
}
void process()
{
send();
while(read()); // process till the queue goes empty
}
private:
bool read()
{
TPCANMsg received = {0};
TPCANStatus result = CAN_Read(PCAN_PCIBUS1, &received, NULL);
if (result == PCAN_ERROR_QRCVEMPTY)
{
return false;
}
else if (result == PCAN_ERROR_OK)
{
// COMMENT: read the message here.
return true;
}
throw std::runtime_error("CAN_Read failed.");
}
void send()
{
// COMMENT: replace the message with yours.
TPCANMsg request = {0};
request.ID = 0;
request.MSGTYPE = PCAN_MESSAGE_STANDARD;
request.LEN = 8;
TPCANStatus result = CAN_Write(PCAN_PCIBUS1, &request);
if (result != PCAN_ERROR_OK)
{
throw std::runtime_error("CAN_Write failed.");
}
}
};
/**
* Control loop for PCAN
*/
void controlLoop(PCANLoop &loop)
{
try
{
loop.process();
}
catch (std::exception &e)
{
ROS_ERROR_STREAM("controlLoop exception:" << e.what());
}
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "my_node");
ros::NodeHandle nh, private_nh("~");
try
{
double control_frequency;
private_nh.param<double>("control_frequency", control_frequency, 50.0);
PCANLoop loop;
ros::CallbackQueue queue;
ros::AsyncSpinner spinner(1, &queue);
ros::TimerOptions control_timer(
ros::Duration(1 / control_frequency),
boost::bind(controlLoop, boost::ref(loop)),
&queue);
ros::Timer control_loop = nh.createTimer(control_timer);
spinner.start();
// Process remainder of ROS callbacks separately, mainly ControlManager related
ros::spin();
}
catch (std::exception &e)
{
ROS_ERROR_STREAM("exception:" << e.what());
}
return 0;
}
We will explain the code later.
We need to describe the new node and its dependency in CMakeLists.txt
and package.xml
.
Now open and edit the src\my_pkg\CMakeLists.txt
file under the workspace.
src\my_pkg\CMakeLists.txt
Below is an example to describe a new node in CMake
.
## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS roscpp)
...
###########
## Build ##
###########
## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
${catkin_INCLUDE_DIRS}
${pcan_INCLUDE_DIRS}
)
## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
add_executable(${PROJECT_NAME}_node src/my_pkg_node.cpp)
## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the
## target back to the shorter version for ease of user use
## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
## Add cmake target dependencies of the executable
## same as for the library above
add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Specify libraries to link a library or executable target against
target_link_libraries(${PROJECT_NAME}_node
${catkin_LIBRARIES}
${pcan_LIBRARIES}
)
#############
## Install ##
#############
# all install targets should use catkin DESTINATION variables
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
## Mark executables for installation
## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html
install(TARGETS ${PROJECT_NAME}_node
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
src\my_pkg\package.xml
Make sure roscpp
in the <depend>
list.
<?xml version="1.0"?>
<package format="2">
<name>my_pkg</name>
...
<depend>roscpp</depend>
...
</package>
Simple CAN Read/Write Loop
In this example, we use Callback and Spinning
from roscpp
to set up a control loop running at 50Hz.
In the callback, we read all the messages from the PCAN message queue and send a empty message to the CAN Bus.
Depending on your CAN devices, you may need to add more protocol-specific implementation on top of the basic I/O.
Step 4: Building the Workspace
Now we have all the code in place. Let's rebuild the workspace again to ensure everything built.
:: Build the workspace
c:\can_ws> catkin_make install
:: Add the install space into the current environment.
c:\can_ws> install\setup.bat
Step 5: Running the ROS Application
Before we launch the application, we need to make sure rosmaster
is up and running.
Start another ROS command prompt and run roscore
.
Now we are ready to run this application.
c:\can_ws> rosrun my_pkg node
Summary
In this tutorial, we walk through the steps of integrate PCAN-Basic
library into your ROS package, how to consume it by an simple CAN read/write loop application.
You are encouraged to proceed on the official PCAN-Basic
documentation to learn more.