From 7c98bbf94904fc3df65204100bf0176aa96f2939 Mon Sep 17 00:00:00 2001 From: Felix Kloss Date: Wed, 24 Jan 2024 11:37:48 +0100 Subject: [PATCH] Add pylon_write_device_user_id_to_camera Add the application to set the cameras ID. --- CHANGELOG.md | 2 + CMakeLists.txt | 13 +++ LICENSE | 5 + doc/pylon.rst | 45 ++++++-- src/pylon_write_device_user_id_to_camera.cpp | 107 +++++++++++++++++++ 5 files changed, 165 insertions(+), 7 deletions(-) create mode 100644 src/pylon_write_device_user_id_to_camera.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 278fb3e..3e91700 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ script `check_camera_sharpness` to easily test different parameters on live camera data. This can be used, for example, to automatically detect if a camera is significantly out of focus. +- Executable `pylon_write_device_user_id_to_camera` to set the "DeviceUserID" of + Pylon cameras. ### Removed - Obsolete script `verify_calibration.py` diff --git a/CMakeLists.txt b/CMakeLists.txt index ddf5f18..e5de08b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,6 +120,19 @@ if (${Pylon_FOUND}) list(APPEND install_targets pylon_list_cameras) + add_executable( + pylon_write_device_user_id_to_camera + src/pylon_write_device_user_id_to_camera.cpp + ) + target_include_directories(pylon_write_device_user_id_to_camera PUBLIC + $ + $ + ${Pylon_INCLUDE_DIRS} + ) + target_link_libraries(pylon_write_device_user_id_to_camera ${Pylon_LIBRARIES}) + list(APPEND install_targets pylon_write_device_user_id_to_camera) + + # Set library names to variables, so we can use the variable instead of the # direct name below. In case, Pylon drivers are not built, the variables # will be empty and thus not cause trouble when used for linking etc. diff --git a/LICENSE b/LICENSE index 1b50431..5db97a6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,8 @@ +This license applies to all files of this repository unless specified +differently in the file's header. + +---- + BSD 3-Clause License Copyright (c) 2019, Max Planck Gesellschaft. diff --git a/doc/pylon.rst b/doc/pylon.rst index 40a9916..e1c83fb 100644 --- a/doc/pylon.rst +++ b/doc/pylon.rst @@ -17,17 +17,48 @@ Install Pylon SDK sudo tar -C /opt -xzf pylonSDK*.tar.gz -4. Install udev-rules to set up permissions for basler USB cameras:: +4. Install udev rules to set up permissions for basler USB cameras:: ./setup-usb.sh -Using Pylon in Singularity -========================== +Using Pylon in Apptainer +======================== -Pylon is currently not installed in the Singularity image so it needs to be -installed on the host system. To be able to use it from inside Singularity, -the installation path needs to be bound when running the image:: +When accessing the cameras from within Apptainer containers, you need to either +install the Pylon SDK in the container, or you can simply bind it from the host system (assuming it's installed there) using - singularity shell -B /opt/pylon5 blmc_ei.sif +.. code-block:: text + apptainer shell --bind=/opt/pylon5 container.sif + +Note that even if the Pylon SDK is installed in the container, it may be needed +to set up the udev rules on the host system (see last step in the section +above). + + +Configuring Cameras +=================== + +The Pylon camera drivers in trifinger_cameras expect a unique "DeviceUserID" +written to the camera to be able to identify it (especially important for the +:cpp:class:`~trifinger_cameras::TriCameraDriver` where the three cameras need to +be distinguished. + +This ID can be set using using the ``pylon_write_device_user_id_to_camera`` +command that is included in the package, using the following steps: + +1. Connect the camera to the computer. **Make sure no other camera is + connected** (the tool will simply write to the first camera found). +2. Run + + .. code-block:: sh + + ros2 run trifinger_cameras pylon_write_device_user_id_to_camera "some_id" + +Once written, the "DeviceUserID" will be displayed by the PylonViewerApp +(unfortunately it's not possible to modifiy it there). + +For the TriFinger robots, we use the IDs "camera60", "camera180" and "camera300" +based on their approximate angular position relative to the fingers, see +:ref:`trifinger_docs:finger_and_camera_names`. diff --git a/src/pylon_write_device_user_id_to_camera.cpp b/src/pylon_write_device_user_id_to_camera.cpp new file mode 100644 index 0000000..b933356 --- /dev/null +++ b/src/pylon_write_device_user_id_to_camera.cpp @@ -0,0 +1,107 @@ +/****************************************************************************** + * Software License Agreement (BSD License) + * + * Copyright (C) 2016, Magazino GmbH. All rights reserved. + * + * Improved by drag and bot GmbH (www.dragandbot.com), 2019 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of Magazino GmbH nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +// taken from +// https://github.com/basler/pylon-ros-camera/blob/ed094fad02eed38af830a052c7420befc6483ef3/pylon_camera/src/pylon_camera/write_device_user_id_to_camera.cpp + +/* + This program will open a Basler Pylon Camera and write a desired camera id. +*/ + +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + std::cerr << "ERROR: No device_user_id set!" << std::endl; + std::cout << "USAGE: write_device_user_id_to_camera DEVICE_USER_ID" + << std::endl; + return 1; + } + + // TODO: regular expression, instead of only catching 2 '_' + std::string desired_device_user_id(reinterpret_cast(argv[1])); + if (desired_device_user_id.empty()) + { + std::cout << "ERROR:" << std::endl; + std::cout << "Your desired device_user_id is empty!" << std::endl; + return 2; + } + + // Before using any pylon methods, the pylon runtime must be initialized. + Pylon::PylonInitialize(); + + try + { + Pylon::CDeviceInfo di; + + // TODO: Multiple cameras connected? -> Don't use first device found + // TODO: Write IP to Camera? + + // Create an instant camera object with the camera device found first. + Pylon::CInstantCamera camera( + Pylon::CTlFactory::GetInstance().CreateFirstDevice(di)); + + camera.Open(); + + while (!camera.IsOpen()) + { + usleep(1000); + } + + GenApi::INodeMap& node_map = camera.GetNodeMap(); + GenApi::CStringPtr current_device_user_id( + node_map.GetNode("DeviceUserID")); + current_device_user_id->SetValue( + Pylon::String_t(desired_device_user_id.c_str())); + + std::cout << "Successfully wrote " << current_device_user_id->GetValue() + << " to the camera " << camera.GetDeviceInfo().GetModelName() + << std::endl; + camera.Close(); + } + catch (GenICam::GenericException& e) + { + // Error handling. + std::cerr << "An exception occurred." << std::endl + << e.GetDescription() << std::endl; + return 3; + } + + // Releases all pylon resources. + Pylon::PylonTerminate(); + + return 0; +}