Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pylon_write_device_user_id_to_camera #36

Merged
merged 1 commit into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
13 changes: 13 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
${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.
Expand Down
5 changes: 5 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
45 changes: 38 additions & 7 deletions doc/pylon.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
107 changes: 107 additions & 0 deletions src/pylon_write_device_user_id_to_camera.cpp
Original file line number Diff line number Diff line change
@@ -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 <pylon/PylonIncludes.h>
#include <unistd.h>
#include <algorithm>
#include <string>

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 '_'

Check failure on line 54 in src/pylon_write_device_user_id_to_camera.cpp

View workflow job for this annotation

GitHub Actions / New TODOs

// TODO: regular expression, instead of only catching 2 '_'
std::string desired_device_user_id(reinterpret_cast<char*>(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

Check failure on line 70 in src/pylon_write_device_user_id_to_camera.cpp

View workflow job for this annotation

GitHub Actions / New TODOs

// TODO: Multiple cameras connected? -> Don't use first device found
// TODO: Write IP to Camera?

Check failure on line 71 in src/pylon_write_device_user_id_to_camera.cpp

View workflow job for this annotation

GitHub Actions / New TODOs

// 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;
}
Loading