ifm / ifm3d

Library and Utilities for working with ifm pmd-based 3D ToF Cameras
https://api.ifm3d.com
Apache License 2.0
108 stars 69 forks source link

Changing parameters on-the-fly #74

Closed Arag24 closed 5 years ago

Arag24 commented 6 years ago

Hi everyone,

I would have a question/need...

In fact I used im3d-examples to test on-the-fly params. Works well with SetTemporaryApplicationParameters method, no problem. However, I would need a bit more piece of info about it.

  1. I would need to get direct string readable on the XML-RPC sesssion to do it from my own. Generally, I always used ifm3d driver and combine all tremendous info from JSON-RPC interface and see what's going on. However for this method, I'm a bit stuck. I found on code, parameters are inserted in a map and the converted into xmlrpc_c::value_structstructure. But, I've no way to easily stream direct string sent to this->_XCallSession("setTemporaryApplicationParameters", params_st);

Could you please give me either, formatted string or a clue to easily trace this formatted string. (i'm a Windows based user)

  1. Last but not least, I could find kv.first == "imager_001/Channel". So I would catch Channel could be taken in consideration, on-the fly? May I miss something (or totally wrong) ?

To be accurate, I'm playing with FW1.23.1522.

graugans commented 6 years ago

@Arag24 am I right you have tested the SetTemporaryApplicationParameters with ifm3d and it works as expected. After this you've tried to do the same with the JSON-RPC web-interface of the camera.

http://192.168.0.69/api/rpc/v1/com.ifm.efector/

Where you have trouble how to format the map, isn't it? The final goal will be a custom XML-RPC interface?

A struct defined in the XML-RPC spec looks like this:

<struct>
   <member>
      <name>lowerBound</name>
      <value><i4>18</i4></value>
      </member>
   <member>
      <name>upperBound</name>
      <value><i4>139</i4></value>
      </member>
   </struct>

The easiest way to trace the string on the wire is the usage of wireshark with it's follow tcp stream functionality it is quite easy to filter out the XML-RPC communication. Running your ifm3d example while wireshark is listening should provide you with the information needed.

Arag24 commented 6 years ago

@graugans Yes you're right, I tested examples of ifm3d and they run as expected...

Howaver my final need is the following : Change Channel parameter on-the-fly (and without ifm3d unfortunately) I know this may not be the best location for this kind of request, but anyway...

Wo what I generally did is playing with ifm3d or JSON-RPC web interface (http://192.168.0.69/api/rpc/v1/com.ifm.efector/) and see what's going in camera before pushing back to my own implementation next.

For Wireshark, you definitely right it helps a lot. (I forgot this wounderful tool and was dealing with my own VS Debugger), but this sniffer is really wonderful for reading http exchanges...

Two statements consequently:

  1. Directly link to ifm3d

When I sniffed change on ExposureTime and ExposureTimeRatio with ifm3d and setTemporaryApplicationParameters everything is running well. But, if I'm adding on same method Channel parameter, here no change appears in camera (even ExposureTime is not changed). Is this channel change possible on-the-fly or not? If not can you prevent usage of additional parameters which could lead to disturb setTemporaryApplicationParameters ?

Below this is copy from Wireshark of this exchange:

->36925 192.168.0.10    192.168.0.69    HTTP/XML    711 POST /api/rpc/v1/com.ifm.efector/session_4846c6365ef676162374627c7341b771/ HTTP/1.1 
<-36927 0.005136    192.168.0.69    192.168.0.10    HTTP/XML    308 HTTP/1.1 200 OK 

Packet 36925:

@S\[vpES@
EPu
?`PKPOST /api/rpc/v1/com.ifm.efector/session_4846c6365ef676162374627c7341b771/ HTTP/1.1
Host: 192.168.0.69
Accept: */*
Content-Type: text/xml
User-Agent: Xmlrpc-c/1.33.14 Curl/7.47.1
Content-Length: 450

<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>setTemporaryApplicationParameters</methodName>
<params>
<param><value><struct>
<member><name>imager_001/Channel</name>
<value><i4>1</i4></value></member>
<member><name>imager_001/ExposureTime</name>
<value><i4>5000</i4></value></member>
<member><name>imager_001/ExposureTimeRatio</name>
<value><i4>1</i4></value></member>
</struct></value></param>
</params>
</methodCall>

Packet 36927:

[vp@S\E&@@
E
P?`wPI5HTTP/1.1 200 OK
Status: 200 OK
Content-Length: 112
Content-Type: text/xml
Date: Fri, 20 Apr 2018 15:33:32 GMT
Server: lighttpd/1.4.35

<?xml version="1.0" encoding="UTF-8"?><methodResponse><params><param><value/></param></params></methodResponse>
  1. I would be interested to know formatting string, at least for ExposureTime and ExposureTimeRatio in JSON-RPC web interface. Indeed, here I never reached to modify them.

Some pieces of info, below:

->242   192.168.0.10    192.168.0.69    HTTP    852 POST /api/rpc/v1/com.ifm.efector/session_ee484bd37406a9b5181326b278ac2131/ HTTP/1.1  (application/x-www-form-urlencoded)
<-244   192.168.0.69    192.168.0.10    HTTP    1021    HTTP/1.1 500 Internal Server Error  (text/html)

Packet 242:

@S\[vpEF`4@
EPN6V_PPOST /api/rpc/v1/com.ifm.efector/session_ee484bd37406a9b5181326b278ac2131/ HTTP/1.1
Host: 192.168.0.69
Connection: keep-alive
Content-Length: 104
Cache-Control: max-age=0
Origin: http://192.168.0.69
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://192.168.0.69/api/rpc/v1/com.ifm.efector/session_ee484bd37406a9b5181326b278ac2131/
Accept-Encoding: gzip, deflate
Accept-Language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7

id=1&method=setTemporaryApplicationParameters&params=%5B%22imager_001%2FExposureTime%22%2C+%225000%22%5D

Packet 244:

[vp@S\Ei@@KE
PV_N:PHTTP/1.1 500 Internal Server Error
Status: 500 Internal Server Error
Content-Length: 772
Content-Type: text/html;charset=utf-8
Date: Fri, 20 Apr 2018 15:14:35 GMT
Server: lighttpd/1.4.35

<div style="border: 1px solid; padding: 2px"><b>Error</b><br>{
    "error": "No such method 'setTemporaryApplicationParameters' in any interface at object path '/session_ee484bd37406a9b5181326b278ac2131' (signature 'a{sv}s')",
    "id": "1",
    "result": null
}
</div><br><form method='post'>id: <input name='id' type='text' value='1'><br><i>(JSON-RPC id, will directly be copied to answer-msg)</i><br>
method: <input name='method' type='text'><br><i>(e.g. org.freedesktop.DBus.Introspectable.Introspect, org.freedesktop.DBus.ListNames)</i><br>params: <input name='params' type='text' value='[]'><br><i>(The bridge now support minimal type-convertion ... //FIXME: atm there are still some parts missing for non-primitiv data ...)</i><br>
<input type='submit'><br></form>

Of course, please have a look with your own device to see if I did any mistakes somewhere....

graugans commented 6 years ago

Okay I guess now I got your point. If you try to change the Channel parameter it seems to behave in an unexpected way. I will take a deeper look into this.

Meanwhile those are the parameters which are/will supported:

Name Description
imager_001/ExposureTime Exposure time of imager. Exposure times are clamped to their allowed range, depending on the exposure mode.
imager_001/ExposureTimeRatio Exposure time ratio of imager
imager_001/Channel Used channel for imager. Values outside of the allowed range of the used exposure mode are ignored, and for non-numeric values the behavior is undefined.
model_001/ObjectSet/set/0/length Depalletizing: length of the object to be found in meters.
model_001/ObjectSet/set/0/width Depalletizing: width of the object to be found in meters.
model_001/ObjectSet/set/0/height Depalletizing: height of the object to be found in meters.
model_001/SlipSheetDetection Depalletizing: enables slip sheet detection
model_001/ObjectType Depalletizing: Object type to be found Allowed values: 0: box 1: bag

Related to the issues with the JSON-Bridge I guess the web service itselfs states the fact that it is only limited in functionality.


(The bridge now support minimal type-convertion ... //FIXME: atm there are still some parts missing for non-primitiv data ...)```
Arag24 commented 6 years ago

@graugans : Thanks 3X.

Reason 1 : I understand JSON-RPC web is surely limited and I would surely need to directly test with ifm3d and not lose my time (and my hair). on it. Reason 2 : Channel parameter is normally supported. Reason 3 : I can read model_001/ObjectSet/set/0/length and some other parameters it would definiftely help me for other applications...

FyFou commented 6 years ago

Hi,

Do you have news about the setting of "Channel" on th fly? I need to set it that way. It's taking too much time to get in edit mode, edit the app, change param, and go back to run.

graugans commented 6 years ago

One side note changing the channel will not work for the more than 30m mode Because the more than 30m mode occupies all frequencies thus no free channel to switch to.

graugans commented 6 years ago

Unfortunately with the current firmware version there is no way of reading back the temporary parameters. This is due to the fact that the method getParameters will always return the value stored in the database. Another thing you have to keep in mind ist the fact that temporary parameters are changed by switching to edit mode. This is for example when you use the ifm vision assistant. In a current development version of the firmware we have implemented a method to query the current temporary parameters

From 7b38ba07e31f9fa8280ff804aeb2676ac9f55342 Mon Sep 17 00:00:00 2001
From: Christian Ege <christian.ege@ifm.com>
Date: Thu, 21 Jun 2018 08:58:19 +0000
Subject: [PATCH] Added support for GetTemporaryApplicationParameters

This will allow a user to read the temporary application parameters.
Which might come handy due to the fact the value can not requested
with the regular ``getParameter`` method. Due to the temporary nature.

Signed-off-by: Christian Ege <christian.ege@ifm.com>
---
 modules/camera/include/ifm3d/camera/camera.h       | 18 ++++++++++++++++
 modules/camera/src/libifm3d_camera/camera.cpp      | 24 ++++++++++++++++++++++
 modules/camera/src/libifm3d_camera/camera_impl.hpp | 17 ++++++++++++++-
 3 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/modules/camera/include/ifm3d/camera/camera.h b/modules/camera/include/ifm3d/camera/camera.h
index 6808219..903a991 100644
--- a/modules/camera/include/ifm3d/camera/camera.h
+++ b/modules/camera/include/ifm3d/camera/camera.h
@@ -51,6 +51,11 @@ namespace ifm3d
   extern IFM3D_CAMERA_EXPORT const unsigned int O3D_TMP_PARAMS_SUPPORT_MINOR;
   extern IFM3D_CAMERA_EXPORT const unsigned int O3D_TMP_PARAMS_SUPPORT_PATCH;

+  extern IFM3D_CAMERA_EXPORT const unsigned int O3D_GET_TMP_PARAMS_SUPPORT_MAJOR;
+  extern IFM3D_CAMERA_EXPORT const unsigned int O3D_GET_TMP_PARAMS_SUPPORT_MINOR;
+  extern IFM3D_CAMERA_EXPORT const unsigned int O3D_GET_TMP_PARAMS_SUPPORT_PATCH;
+
+
   /**
    * Software interface to an ifm 3D camera
    *
@@ -247,6 +252,19 @@ namespace ifm3d
       const std::unordered_map<std::string, std::string>& params);

     /**
+     * Get temporary application parameters in run mode.
+     *
+     * The changes are not persistent and are lost when entering edit mode or
+     * turning the device off. For details about changing parameters take a look
+     * at ::SetTemporaryApplicationParameters
+     *
+     * @return The parameters which have been set on the camera.
+     *
+     * @throw ifm3d::error_t upon error
+     */
+    virtual std::unordered_map<std::string, std::string> GetTemporaryApplicationParameters();
+
+    /**
      * Sends a S/W trigger to the camera over XMLRPC.
      *
      * The O3X does not S/W trigger over PCIC, so, this function
diff --git a/modules/camera/src/libifm3d_camera/camera.cpp b/modules/camera/src/libifm3d_camera/camera.cpp
index 203dc63..7db0fba 100644
--- a/modules/camera/src/libifm3d_camera/camera.cpp
+++ b/modules/camera/src/libifm3d_camera/camera.cpp
@@ -59,6 +59,11 @@ const unsigned int ifm3d::O3D_TMP_PARAMS_SUPPORT_MAJOR = 1;
 const unsigned int ifm3d::O3D_TMP_PARAMS_SUPPORT_MINOR = 20;
 const unsigned int ifm3d::O3D_TMP_PARAMS_SUPPORT_PATCH = 0;

+const unsigned int ifm3d::O3D_GET_TMP_PARAMS_SUPPORT_MAJOR = 1;
+const unsigned int ifm3d::O3D_GET_TMP_PARAMS_SUPPORT_MINOR = 23;
+const unsigned int ifm3d::O3D_GET_TMP_PARAMS_SUPPORT_PATCH = 1750;
+
+
 //================================================
 // A lookup table listing the read-only camera
 // parameters
@@ -265,6 +270,25 @@ ifm3d::Camera::SetTemporaryApplicationParameters(
   this->pImpl->SetTemporaryApplicationParameters(params);
 }

+std::unordered_map<std::string, std::string>
+ifm3d::Camera::GetTemporaryApplicationParameters()
+{
+  //
+  // NOTE: we "fail" silently here. Assumption is a closed loop check by the
+  // user to see if/when the temp params take effect.
+  //
+  if (this->IsO3D() &&
+      (! this->check_min_ifm_version(ifm3d::O3D_GET_TMP_PARAMS_SUPPORT_MAJOR,
+                                     ifm3d::O3D_GET_TMP_PARAMS_SUPPORT_MINOR,
+                                     ifm3d::O3D_GET_TMP_PARAMS_SUPPORT_PATCH)))
+    {
+      LOG(WARNING) << "Getting temp params not supported by this device!";
+      return std::unordered_map<std::string, std::string>();
+    }
+
+  return this->pImpl->GetTemporaryApplicationParameters();
+}
+
 void
 ifm3d::Camera::ForceTrigger()
 {
diff --git a/modules/camera/src/libifm3d_camera/camera_impl.hpp b/modules/camera/src/libifm3d_camera/camera_impl.hpp
index f833284..03d48f6 100644
--- a/modules/camera/src/libifm3d_camera/camera_impl.hpp
+++ b/modules/camera/src/libifm3d_camera/camera_impl.hpp
@@ -95,6 +95,7 @@ namespace ifm3d
     void SetOperatingMode(const ifm3d::Camera::operating_mode& mode);
     void SetTemporaryApplicationParameters(const std::unordered_map<std::string,
                                            std::string>& params);
+    std::unordered_map<std::string, std::string> GetTemporaryApplicationParameters();
     std::vector<std::uint8_t> ExportIFMConfig();
     std::vector<std::uint8_t> ExportIFMApp(int idx);
     void ImportIFMConfig(const std::vector<std::uint8_t>& bytes,
@@ -476,7 +477,14 @@ ifm3d::Camera::Impl::value_struct_to_map(const xmlrpc_c::value_struct& vs)
   std::unordered_map<std::string, std::string> retval;
   for (auto& kv : resmap)
     {
-      retval[kv.first] = std::string(xmlrpc_c::value_string(kv.second));
+      if( xmlrpc_c::value::TYPE_INT == kv.second.type() )
+   {
+          retval[kv.first] = std::to_string(xmlrpc_c::value_int(kv.second));
+   }
+      else
+       {
+         retval[kv.first] = std::string(xmlrpc_c::value_string(kv.second));
+       }
     }

   return retval;
@@ -709,6 +717,13 @@ ifm3d::Camera::Impl::SetTemporaryApplicationParameters(
                       params_st);
 }

+std::unordered_map<std::string, std::string>
+ifm3d::Camera::Impl::GetTemporaryApplicationParameters()
+{
+ return this->value_struct_to_map(this->_XCallSession("getTemporaryApplicationParameters"));
+}
+
+
 std::vector<std::uint8_t>
 ifm3d::Camera::Impl::ExportIFMConfig()
 {
-- 
2.7.4

With the latest development firmware and the patch above plus the following patch for the ifm3d-examples repo you can see the parameters are updated as expected.

diff --git a/ex-exposure_times.cpp b/ex-exposure_times.cpp
index dfe68d9..e17da0b 100644
--- a/ex-exposure_times.cpp
+++ b/ex-exposure_times.cpp
@@ -144,14 +144,22 @@ int main(int argc, const char **argv)
             {
               std::cout << 10000 << std::endl;
               params["imager_001/ExposureTime"] = "10000";
+              params["imager_001/Channel"] = "1";
             }
           else
             {
               std::cout << 5000 << std::endl;
               params["imager_001/ExposureTime"] = "5000";
+              params["imager_001/Channel"] = "2";
             }

           cam->SetTemporaryApplicationParameters(params);
+          auto temp_param = cam->GetTemporaryApplicationParameters();
+         std::cout << "Current temporary parameters: " << std::endl;
+          for (auto const &pair: temp_param)
+            {
+              std::cout << "{ \"" << pair.first << "\": \"" << pair.second << "\" }" << std::endl;
+            }
         }
     }

The time for updating the temporal parameters is typically 1-2 frames on the camera. This might be longer due to buffering on the embedded or PC TCP/IP socket. Related to the Channel feature itself I do recommend to follow the instructions on the following libo3d3xx issue #46

FyFou commented 6 years ago

My issue is, i have only one camera by robot, but they are interfering each other when they cross each other on the way (below 5m). There is no hardware trigger possible.

They are both in continuous mode. I tried to set up the channel by going into edit mode, edit the app, change the channel, validate, stop edit mode, set run mode. But this is taking about a second. This mean a second without image when two robot cross each other.

I need to go below 0.3 second to get acceptable result. That's why i'm interested by changing the channel on the fly. But it seem not to change the channel when i try (thinking twice, i should retry it).

Is there an other way for me to get that result?

graugans commented 6 years ago

I do confirm there is an bug in the setTemporaryApplicationParameters on the camera. The channel is reported to be switched but on chip level the channel has not switched. Sorry about all this back and forth. I will try to fix this asap.

Arag24 commented 5 years ago

Solved with 1.23.2848 FW -> Closed