IntelRealSense / realsense-ros

ROS Wrapper for Intel(R) RealSense(TM) Cameras
http://wiki.ros.org/RealSense
Apache License 2.0
2.54k stars 1.75k forks source link

when open "rs_camera.launch" ,how to use other code to adjust SR305's motion_range ,gain...etc #1168

Closed weseu closed 4 years ago

weseu commented 4 years ago

When I open "rs_camera.launch",I want to use another c++ code to dynamic Adjustment it's motion_range , gain....and so on.

Maybe I can use the ddynamic_reconfigure package,but I don't know how to do......

can you help me....give me some direction......

MartyG-RealSense commented 4 years ago

Apologies for the delay in responding. I was very carefully researching the options available for control of these options for the SR305. I believe that C++ is going to be the best method to do so.

Scripting for motion_range can be found here:

https://github.com/IntelRealSense/librealsense/issues/3185

An example of C++ code for changing gain and exposure manually is here:

https://github.com/IntelRealSense/librealsense/issues/2024#issuecomment-404067092

drfg0119 commented 4 years ago

Hi @MartyG-RealSense , I am just curious about how to set the value by using ddynamic_reconfigure methods. Because I am trying to write a node can loop the value in a range(for example: motion range 0~60) when run the rs_camera.launch, should I write a register to save the value(EX: registerEnumVariable) and then publish it ? I followed the base_realsense_node.cpp in Line 383 to 486, which is under realsense-ros. Or even I don't need to do this...

By the way, I didn't know how to write the code like this

rs2::pipeline p; auto profile = p.start(); auto dev = profile.get_device(); auto sensor = dev.query_sensors().front(); sensor.set_option(RS2_OPTION_MOTION_RANGE, ...); sensor.set_option(RS2_OPTION_CONFIDENCE_THRESHOLD, ...); sensor.set_option(RS2_OPTION_FILTER_OPTION, ...);

Could you please tell me how should I do(like which workspace should I under, which headfile should I include, or any sample code I could follow)? thank you.

MartyG-RealSense commented 4 years ago

Hi @drfg0119

If you are using an SR305 like @weseu then this is a difficult question to advise on in regard to using ROS and dynamic reconfigure. This is because I do not know whether SR305 is compatible with the ROS wrapper, even though the SR305 is basically an SR300 inside its casing. SR300 is compatible but I do not have official information about whether SR305 is compatible.

To achieve what you would like to do with ROS, I suspect that you would have to do two things, if you have an SR305 and it can be used as an SR300 with the ROS wrapper:

  1. Use the older 'legacy' version of Librealsense.

https://github.com/IntelRealSense/librealsense/tree/v1.12.1

  1. Use the realsense_camera module that contains the SR300-compatible command ~f200_motion_range (the F200 was the predecessor of the SR300, but they have similar technology and so commands for the F200 tend to work with SR300).

http://wiki.ros.org/realsense_camera#SR300_Dynamically_Reconfigurable_Parameters

I would recommend waiting for confirmation from @doronhi the RealSense ROS developer about whether the above plan is correct though, so that you do not waste your time. I apologise that I could not provide more certainty in my advice on this particular case.

drfg0119 commented 4 years ago

Hi @MartyG-RealSense , haha OK that's fine, thank you, but I can run the rqt_reconfigure to set values in the "coded-light sensor" node dynamically, so I thought that is available for me to write a node to control SR305.

But, could you please help me to understand the code written by @dorodnic here ? I want to know how should I do(like which workspace should I under, which headfile should I include, or any sample code I could follow) to write it?

Thank you for your attention.

rs2::pipeline p; auto profile = p.start(); auto dev = profile.get_device(); auto sensor = dev.query_sensors().front(); sensor.set_option(RS2_OPTION_MOTION_RANGE, ...); sensor.set_option(RS2_OPTION_CONFIDENCE_THRESHOLD, ...); sensor.set_option(RS2_OPTION_FILTER_OPTION, ...);

MartyG-RealSense commented 4 years ago

@drfg0119 The code example by Dorodnic is in a programming language called C++. To create a C++ program, it is recommended that compiler software such as Microsoft Visual Studio is used. A free version of Visual Studio is Visual Studio Community.

https://visualstudio.microsoft.com/vs/community/

The link below has some guidance about integrating Librealsense into a project that you have created yourself.

https://github.com/IntelRealSense/librealsense/issues/4277

There is also a 'getting started' project for beginners.

https://github.com/zivsha/librealsense/tree/getting_started_example/examples/getting-started

Once you have a 'development environment' set up in a program such as Visual Studio then you will be in a position to use scripting code such as the sample that Dorodnic provided.

The basics of the structure of Dorodnic's sample is that the first few lines set up a 'pipeline' for the camera's processes to work within and then tell Librealsense how to find your camera with a device 'profile'. The last few lines - set.option commands - configure a particular aspect of the camera's functions, such as its motion range value.

drfg0119 commented 4 years ago

Hi @MartyG-RealSense , I have written a node named controller like this, because I didn't know how to deal with the protected member in class options which is under rs_option.hpp, so I used inheritance to make a new class called controller, but when I found there is error when it run into the function defined myself like ctr.get_MvR(option), then I check the function step by step, I found bug is error::handle(e) in my hpp file. Is there any idea could suggest? I'll appreciate.

#include </opt/ros/melodic/include/ros/ros.h>
#include </home/nvidia/catkin_ws/src/ddynamic_reconfigure/include/ddynamic_reconfigure/ddynamic_reconfigure.h>
#include <string>
#include <map>
#include <iostream>
#include <fstream>
#include "/home/nvidia/librealsense/include/librealsense2/h/rs_option.h"
#include "/home/nvidia/librealsense/include/librealsense2/h/rs_types.h"
#include <algorithm>
#include <cctype>
#include <mutex>
#include "controller.hpp"

using namespace ddynamic_reconfigure;

int main(int argc, char **argv)
{

    ROS_INFO("Spinning node");
    ros::init(argc, argv, "controller");
    ros::NodeHandle nh;
    ddynamic_reconfigure::DDynamicReconfigure ddynrec;
    rs2::controller ctr; // like rs2::options sensor

    rs2_option option = static_cast<rs2_option>(16);  //no.16 is RS2_OPTION_MOTION_RANGE
    const auto sensor_option_value = ctr.get_MvR(option); // like sensor.get_option(option)
    auto option_value = int(sensor_option_value);

    ros::Rate loop_rate(10);
    int c = 0;
    while (ros::ok())
    {
        c++;
        option_value = 0;
        if(!(c%10))
        {
            option_value+=5;
            if(option_value > 60)
                option_value = 0;
        }
        ctr.set_MvR(option, option_value); // like sensor.set_option(option, option_value);

        ddynrec.registerVariable<int>(
            ctr.get_MvR_name(option), int(option_value),
            [option, ctr](int new_value) { ctr.set_MvR(option, new_value); },
            ctr.get_MvR_description(option));

        loop_rate.sleep();
    }
    ROS_INFO("Spinning node shutdown...");
    return 0;
}

Here is the controller.hpp written myself, it's copy from rs_option.hpp

#include "/usr/local/include/librealsense2/hpp/rs_options.hpp"
#include "/usr/local/include/librealsense2/hpp/rs_types.hpp"

namespace rs2
{
    class controller : public options
    {
    public:

        const char* get_MvR_description(rs2_option option) const
        {
            rs2_error* e = nullptr;
            auto res = rs2_get_option_description(_ctr, option, &e);
            error::handle(e);
            return res;
        }

        const char* get_MvR_name(rs2_option option) const
        {
            rs2_error* e = nullptr;
            auto res = rs2_get_option_name(_ctr, option, &e);
            error::handle(e);
            return res;
        }

        const char* get_MvR_value_description(rs2_option option, float val) const
        {
            rs2_error* e = nullptr;
            auto res = rs2_get_option_value_description(_ctr, option, val, &e);
            error::handle(e);
            return res;
        }

        float get_MvR(rs2_option option) const
        {
            rs2_error* e = nullptr;
            auto res = rs2_get_option(_ctr, option, &e);
            error::handle(e);
            return res;
        }

        void set_MvR(rs2_option option, float value) const
        {
            rs2_error* e = nullptr;
            rs2_set_option(_ctr, option, value, &e);
            error::handle(e);
        }

        std::vector<rs2_option> get_supported_MvR()
        {
            std::vector<rs2_option> res;
            rs2_error* e = nullptr;
            std::shared_ptr<rs2_options_list> options_list(
                rs2_get_options_list(_ctr, &e),
                rs2_delete_options_list);

            for (auto opt = 0; opt < rs2_get_options_list_size(options_list.get(), &e);opt++)
            {
                res.push_back(rs2_get_option_from_list(options_list.get(), opt, &e));
            }
            return res;
        }

        explicit controller(rs2_options* o = nullptr) : _ctr(o)
        {
        }

        controller& operator=(const controller& other)
        {         
            _ctr = other._ctr;
            return *this;
        }

        controller(const cpntroller& other) : _ctr(other._ctr) {}

        virtual ~controller() = default;

        template<class T>
        controller& operator=(const T& dev)
        {
            _ctr = (rs2_options*)(dev.get());
            return *this;
        }

        rs2_options* _ctr;
    };
}
drfg0119 commented 4 years ago

I set the print for finding the bug, here is in cpp. image

Here is under hpp. image

Here is the result. image

Please help me, thank you!

MartyG-RealSense commented 4 years ago

I do not have experience of writing ROS node scripts unfortunately, so are unable to debug them.

Is your include for controller.hpp meant to be expressed as #include "controller.hpp" or should it be #include

drfg0119 commented 4 years ago

Are they different !!? I dont know haha, I'm just new in programming sorry...

But I try to change "" to <>, the comment said it "no such file or directory".

MartyG-RealSense commented 4 years ago

Ok, looking at your other scripts, using " " seems to be valid too. As I said, my programming knowledge is still developing. :)

Since you did not specify a folder path in #include "controller.hpp" , is the file controller.hpp located in the same folder as the node script that is including it?

drfg0119 commented 4 years ago

Oh yes, I put the .hpp and .cpp under same folder! Thank you haha

MartyG-RealSense commented 4 years ago

You are very welcome! Is your problem solved now, please?

drfg0119 commented 4 years ago

Not yet, that is not the problem haha...

MartyG-RealSense commented 4 years ago

If there is a bug in the node script then I do not have the programming knowledge to advise on that, sadly. I will refer the problem to an Intel support manager for advice. I apologise for the delay that this will cause to your project in the meantime.

drfg0119 commented 4 years ago

Don't mind it, thank you for your attention.

drfg0119 commented 4 years ago

hey I solved the problem, because I didn't add this after main code haha.

image

But I need to face another problem now haha, the "e.get_failed_function()" throw the info(said "rs2_get_option"),and "e.get_failed_args()" also throw the info(said "option:nullptr, option:Filter Option"), finally the "e.what()" throw the info(said "null pointer passed for argument"option"."). Totally, the full sentence is RealSense error calling rs2_get_option(option:nullptr, option:Filter Option): null pointer passed for argument "options". is there any idea could help me? thanks.

MartyG-RealSense commented 4 years ago

Great news that you solved your original problem!

Regarding the new problem, there was someone who created a workaround for a similar error. The workaround made the program keep trying until it worked.

https://github.com/IntelRealSense/librealsense/issues/3892#issuecomment-488828666

catch (const rs2::error & e) { std::cerr << "RealSense error calling " << e.get_failed_function() << "(" << e.get_failed_args() << "):\n " << e.what() << std::endl; }

drfg0119 commented 4 years ago

but there isn't the same function, should I follow their solution? And then I change my code, I realize that there is an class called sensor could do the same thing I want, so I delete my controller.hpp haha, but I am confused that still has same problem said: RealSense error calling rs2_get_option(option:nullptr, option:Filter Option): null pointer passed for argument "options". did I use the wrong way...?

here is my code. thanks

#include </opt/ros/melodic/include/ros/ros.h>
#include </home/nvidia/catkin_ws/src/ddynamic_reconfigure/include/ddynamic_reconfigure/ddynamic_reconfigure.h>
#include </home/nvidia/librealsense/include/librealsense2/rs.hpp>
#include <vector>
#include <utility>
#include <map>
#include <iomanip>
#include <iostream>

using namespace ddynamic_reconfigure;

int main(int argc, char **argv) try
{
    ROS_INFO("Spinning node");
    printf("c1\n");
    ros::init(argc, argv, "controller");
    printf("c2\n");
    ros::NodeHandle nh;
    printf("c3\n");
    ddynamic_reconfigure::DDynamicReconfigure ddynrec;
    printf("c4\n");
  //rs2::controller ctr;
    rs2::sensor sensor;
    printf("c5\n");

    rs2_option option;
    printf("c6\n");
    option  = static_cast<rs2_option>(16);
    printf("c7\n");
    const auto sensor_option_value =  sensor.get_option(option);
    printf("c8\n");
    auto option_value = int(sensor_option_value);

    ros::Rate loop_rate(10);
    int c = 0;
    while (ros::ok())
    {
        c++;
        option_value = 0;
        if(!(c%10))
        {
            option_value+=5;
            if(option_value > 60)
                option_value = 0;
        }
        sensor.set_option(option, option_value);

        ddynrec.registerVariable<int>(
            sensor.get_option_name(option), option_value,
            [option, sensor](int new_value) { sensor.set_option(option, new_value); },
            sensor.get_option_description(option));

        ddynrec.publishServicesTopics();
        loop_rate.sleep();
    }
    ROS_INFO("Spinning node shutdown...");
    return EXIT_SUCCESS;

}
catch (const rs2::error & e)
{
    std::cerr << "RealSense error calling " << e.get_failed_function() << "(" << e.get_failed_args() << "):\n    "  << e.what() << std::endl;
    return EXIT_FAILURE;
}

catch (const std::exception& e)
{
    std::cerr << e.what() <<std::endl;
    return EXIT_FAILURE;
}

And then there is an compile warning, is it OK...??? image

and this is the error image

MartyG-RealSense commented 4 years ago

Oh, you already put in error catch code before the link I gave you. Sorry about that.

@doronhi sorry to bother you. Can you check the code above when you get an opportunity please to see why @drfg0119 might be getting null pointer errors. Thanks!

drfg0119 commented 4 years ago

Hi @MartyG-RealSense and @doronhi , here the code is my latest version, I face the problem that I couldn't run the rs_camera.launch with my node together. Could you please help me..? Thanks!

#include "ros/ros.h"
#include </home/nvidia/catkin_ws/src/ddynamic_reconfigure/include/ddynamic_reconfigure/ddynamic_reconfigure.h>
#include </home/nvidia/librealsense/include/librealsense2/rs.hpp>
#include <vector>
#include <utility>
#include <map>
#include <iomanip>
#include <iostream>
#include <algorithm>

static rs2::device get_a_realsense_device()
{
    rs2::context ctx;
    rs2::device_list devices = ctx.query_devices();
    rs2::device selected_device;
    selected_device = devices[0]; //SR300
    return selected_device;
}

static rs2::sensor get_a_sensor_from_a_device(const rs2::device& dev)
{
    std::vector<rs2::sensor> sensors = dev.query_sensors();
    return sensors[0]; //Coded-Light Depth Sensor
}

int main(int argc, char **argv) try
{
    ROS_INFO("Spinning node");
    ros::init(argc, argv, "controller");
    ros::NodeHandle nh;
    printf("c1\n");

    rs2::device dev = get_a_realsense_device();
    printf("c2\n");

    rs2::sensor sensor;
    printf("c3\n");

    sensor = get_a_sensor_from_a_device(dev);
    printf("c4\n");

    rs2_option option;
    printf("c5\n");

    option  = static_cast<rs2_option>(15); //Motion Range
    printf("c6\n");
    std::cout << option << std::endl;

    float sensor_option_value = sensor.get_option(option);
    printf("c7\n");
//  printf("%d\n", sensor_option_value);

    auto option_value = int(sensor_option_value);

    ros::Rate loop_rate(1000);

    int c = 0;
    option_value = 0;
    while (ros::ok())
    {
        c++;
        if(c!=0)
        {
            option_value+=5;
            printf("%d\n",option_value);
            if(option_value > 60)
                option_value = 0;
        }
        printf("ya1\n");
        sensor.set_option(option, option_value);
        printf("%d\n",option_value);

        printf("c8\n");
        ros::spinOnce();
        loop_rate.sleep();
    }
    ROS_INFO("Spinning node shutdown...");
    return EXIT_SUCCESS;

}
catch (const rs2::error & e)
{
    std::cerr << "RealSense error calling " << e.get_failed_function() << "(" << e.get_failed_args() << "):\n    "  << e.what() << std::endl;
    return EXIT_FAILURE;
}

catch (const std::exception& e)
{
    std::cerr << e.what() <<std::endl;
    return EXIT_FAILURE;
}

image

drfg0119 commented 4 years ago

Hi, I am just thinking how to fix the device-conflicting problem, I have 2 idea like:

  1. Find the device address under the realsense2_camera when I launch the rs_camera.launch, then include it to my code.
  2. Put my main( ) code under the base_realsense_node.cpp.

But I don't know how to do it, or maybe I am wrong. Could you please help me? Thanks!

MartyG-RealSense commented 4 years ago

The "failed to set power state" error sounds like more power demand is being put on the computer's USB ports by the camera than it can cope with. This error has sometimes been seen in setups where more than one camera has been added to the same computer, and small computing boards such as Raspberry Pi may be more liable than full PCs to encounter this error.

In situations where there is a single camera attached and insufficient power for the camera to be detected reliably, a typical solution would be to attach the camera to a mains electricity powered USB 3 hub instead of attaching the camera directly to the computer. With a powered hub, the camera no longer has to take its power from the computer. A hub can supply 12 watts of power, which is more than enough for the average 2 watt power demand of a single camera.

Could you please provide details please of what kind of computer / computing device you are using, and which operating system you are using (Windows, Linux, etc). Thanks!

drfg0119 commented 4 years ago
Required Info
Camera Model { SR305 }
Firmware Version 3.27.3.0
Operating System & Version Linux (Ubuntu 18.04)
Kernel Version (Linux Only) (Jetpack 4.2.2)
Platform NVIDIA Jetson TX2
SDK Version { RealsenseViewer 2.32.1 }
Language {ROS(Melodic) / C++ }
Segment {Robot }

But I only connect with one cam.. I am only allowed to run rs_camera.launch or my-node one by one. If I run both of them at the same time, this is the result.. failed to set power state

MartyG-RealSense commented 4 years ago

If your launch file and node are both using the default configuration of SR305 instead of a custom configuration, each one might try to open 2 streams (the default SR305 configuration) and overwhelm the computing board with power demand, similar to the SR305 case in the link below.

https://github.com/IntelRealSense/librealsense/issues/5782#issuecomment-582077781

drfg0119 commented 4 years ago

Yes, I launch nodes both using the default configuration of SR305, but I only want to open "one" stream, that shouldn't be a conflicting issue here... Thank you for your attention.

BTW, I'm trying another way to write my auto&dynamic-setting-parameter-controller haha, I want to focus on how to write a client node because there is a service called "set_parameters" under ddynamic_reconfigure project.

Is there any method could help me? I have no idea about where the Config in librealsense is, I want to find them then I can use the parameter.

If there is any idea could provide, please help me. Thanks

MartyG-RealSense commented 4 years ago

I apologise for the delay in responding further, as I was researching your wish to write a C++ node that could access dynamic reconfigure, and set_parameters in particular,

I first found a beginners tutorial for creating a C++ ROS node that uses dynamic reconfigure.

http://wiki.ros.org/dynamic_reconfigure/Tutorials/SettingUpDynamicReconfigureForANode%28cpp%29

The link below is an interesting looking reference regarding use of set_parameters in a ROS dynamic reconfigure node:

https://stackoverflow.com/questions/21999143/use-dynamic-reconfiguration-to-set-the-parameter-value-in-ros/22080386

i hope that the above information will provide some useful insights.

drfg0119 commented 4 years ago

Hi, I'm really appreciate for your attention.

I want to know how to get the Config(EX: dynamic_tutorials::TutorialsConfig config ) there were parameters already declared in there.

The Config I want to find is under coded_light_depth_sensor under realsense2_camera .

Thank you, but I've already know how beginners tutorial declare their service, because they define their own parameters, but I don't know how did realsense2_camera work, would you please help me? Thanks

MartyG-RealSense commented 4 years ago

I did not have much luck finding a C++ RealSense node script that refers to "Coded-Light Depth Sensor" except for the one in the link below.

https://github.com/intel/ros2_intel_realsense/blob/master/realsense_ros2_camera/src/realsense_camera_node.cpp#L320

drfg0119 commented 4 years ago

Here also found one haha. https://github.com/IntelRealSense/librealsense/blob/master/src/ivcam/sr300.h#L303

Sorry, I didn't describe my problem clearly.

The reason why I want to find "Config" under coded_light_depth_sensor is I want to write a method that could help me to find the definition(EX: value range, value maximum and minimum...) of the parameter(EX: motion_range).

Then, I can use the declared parameter do everything I want.

Just like the following code: https://github.com/WelinLee/ROS_dynamic_reconfig/blob/master/ros_dynamic_test/src/dyn_client.cpp#L25

then I want to do a comparison between this one: https://github.com/pal-robotics/ddynamic_reconfigure/blob/kinetic-devel/test/test_ddynamic_reconfigure.cpp#L43

Thank you.

MartyG-RealSense commented 4 years ago

I must emphasise that I do not have any experience of programming ROS node scripts, so I can only answer on this subject with what I can find on the internet that others have written. With very specific questions like this one about SR300, dynamic reconfigure and motion range parameters, there is no information that I can find that I can use to offer a suggestion.

I still also do not know if realsense2_camera is capable of providing a minimum and maximum value for motion_range like the order realsense_camera module can.

The only option available to me is to tag @doronhi again. I do apologise.

drfg0119 commented 4 years ago

Thank you, I'll keep going and wait for your supports. HaHa

MartyG-RealSense commented 4 years ago

@drfg0119 I apologise that you did not receive a further response. Do you still require assistance with this case please? thanks for your patience!

drfg0119 commented 4 years ago

Yes @MartyG-RealSense , thank for your attention, I have a last question !! I am curious about that could I set the value like gain or offset on IR camera(not the RGB) of SR305 ? I didn't find them under the coded-light depth sensor, but I thought there might be a code I could tune the value. Could you please help me ? Thank you very much.

MartyG-RealSense commented 4 years ago

It's a difficult question. The original realsense_camera ROS module for SR300 and Librealsense1 had support for changing values like gain by using dynamic reconfigure.

http://wiki.ros.org/realsense_camera#SR300_Dynamically_Reconfigurable_Parameters

However, I do not have any documentation that these features are still supported in the current realsense2_camera ROS module for Librealsense2.

If you are using ROS Kinetic then there is the possibility that you might be able to use librealsense1 and realsense_camera to achieve access to these SR300 functions, if those old programs are able to recognise an SR305 as an SR300.

@doronhi can you provide guidance about what SR300-specific features could be accessed with an SR305 and realsense2_camera, please?

doronhi commented 4 years ago

Hi, I haven't got an access to an SR305 for the last few weeks. Hopefully next week. I see reference to SR305 in the code so, In the meanwhile, could you tell me if you tried using realsense2_camera wrapper with SR305? Didn't it work? Could you add the log (from the screen)? If it works you should have all the options available with rqt_reconfigure. Which one didn't you see there?

drfg0119 commented 4 years ago

Hi @doronhi ,

I see reference to SR305 in the code so, In the meanwhile, could you tell me if you tried using realsense2_camera wrapper with SR305? Didn't it work? Could you add the log (from the screen)?

I've already solved the programming problem, thanks for your following.

If it works you should have all the options available with rqt_reconfigure. Which one didn't you see there?

However, I am just curious about that is there a option named Gain (like UVC image gain applied on RGB camera) is under IR camera? Thank you.

doronhi commented 4 years ago

I'm glad you solved it. Closing the ticket now, then.

There is a "Gain" option for IR camera. You can check it out if you run rosrun rqt_reconfigure rqt_reconfigure. It's under camera->stereo_module->gain. Make sure to unmark "camera->stereo_module->enable_auto_exposure" for your gain modifications to apply. Watch the effects on the "infra1/image_rect_raw" topic using rqt_image_view (or some other ROS viewer).