Homepage GitHub

How configure node params?


(Sergey F1987) #1

I fixed my troubles, that I described below, but now I have a question about one thing, that I still cannot understand completely.
I want define some inner params for node (configure node). I read this tutorial.
https://uavcan.org/Implementations/Libuavcan/Tutorials/7._Remote_node_reconfiguration/
Did I understand right, that I must initialize and launch ParamServer (Remote node section) and then set (or read) params through uavcan::protocol::param::GetSet::Request (Response);
I need add (define) a new param in node (in node space) for reconfiguring it at next. How can do I this?

I got answer as…
" The library is interfaced with your application via the uavcan::IParamManager interface:
It is entirely up to you to decide how to handle your configuration parameters, how to add a new one, how to modify them, and so on."

But… How??? RRRRR!!! If I had not tried to do this, I would not have written this post. My program still cannot configure params.


(Pavel Kirienko) #2

Let’s have a look at your program. Particularly, let us have a look at your implementation of the uavcan::IParamManager interface.


(Sergey F1987) #3

Hello.
I try to write value to new param in my node. After I want to get it back.

I try to add param ‘frequence’ to space of node. I defined it in struct before:

static struct Params
{
    int freq = 0;
} configuration;

Then I defined all methods for virtual class IParamManager. One of them is assigning:

void assignParamValue(const Name& name, const Value& value) override
{
    if (name == "freq")
    {
        if (value.is(uavcan::protocol::param::Value::Tag::integer_value))
        {
            configuration.freq = *value.as<uavcan::protocol::param::Value::Tag::integer_value>();
        }
    }
}

And then I try to write value to ‘freq’-named param. First I started server:

uavcan::ParamServer server(node);
er_code = server.start(&p_man);
if(er_code < 0)
{
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);
}
node.setRestartRequestHandler(&restart_handler);

Server starts with er_code=0, that I think is OK (not <0)
After I set my node to Operational mode, init response and request

//set node to active mode
node.setModeOperational();
//Init standart service operations
uavcan::protocol::param::GetSet::Response resp;
uavcan::protocol::param::GetSet::Request req;

Setting request index and name (‘freq’). I try to write new value to my ‘freq’ param and read it back from node. But first.value of result returns (in performBlockingServiceCall) with error (<0), and I cannot read value to frequency variable

req.index=1;  //set my index
req.name="freq"; //set valid name
req.value=resp.value;  //not sure in it
//try to write value from defined UPDATE_RATE_HZ
req.value.to<uavcan::protocol::param::Value::Tag::integer_value>()=UPDATE_RATE_HZ; //set param
//get result of service
auto result = performBlockingServiceCall<uavcan::protocol::param::GetSet>(node,node_id,req);
//get frequency from params (read value FAIL)
frequency=result.second.value.to<uavcan::protocol::param::Value::Tag::integer_value>();

(Pavel Kirienko) #4

What is the value of the returned error code?

P.S. This is not directly related to your problem, but you might want to know that closures use heap memory, which is probably not what you want on an embedded system. Consider avoiding them; use plain functions, member functions, or non-capturing lambdas instead.


(Sergey F1987) #5

I get result.first == -2
As in ‘performBlockingServiceCall’ func I get:

success = result.isSuccessful();  //  false returned

and call_res == -2 in:

const int call_res = client.call(remote_node_id, request); // -2

And I have global FAIL result for ‘performBlockingServiceCall’ calling

But server starts with ‘0’ code, that is means OK (not < 0)

I tried even only read params according to: https://uavcan.org/Implementations/Libuavcan/Tutorials/7._Remote_node_reconfiguration/
But it also returns with fail:

auto res = performBlockingServiceCall<uavcan::protocol::param::GetSet>(node, remote_node_id, req);
        if (res.first < 0)
        {
            throw std::runtime_error("Failed to get param: " + std::to_string(res.first));
        }

I have also res.first == -2, as in my task before (result.first == -2)


(Pavel Kirienko) #6

As you can see in error.hpp, error code 2 means ErrInvalidParam. Most likely the value of node_id is invalid, check that.


(Sergey F1987) #7

Ok… But before I init my node directly with id=1:
int node_id=1; //node id
uint32_t v_adc; //var for value from ADC
int frequency; //var of frequency for Airspeed sending
auto& node = getNode(); //get node
node.setNodeID(node_id); //set node ID
node.setName(“AirSensor”); //set name

When I start node, it’s returns OK. So I can suggest that node_id set to ‘1’


(Pavel Kirienko) #8

Sorry, I was referring to the server node ID that you are passing to performBlockingServiceCall():

auto result = performBlockingServiceCall<uavcan::protocol::param::GetSet>(node,node_id,req);

(Sergey F1987) #9

I m a little confuset. I wrote a test little code.
I wrote in ‘int main’ func

   int node_id=4 //node id
   int remote_node_id=5; //remote node id
   auto& node = getNode(); //get node
   node.setNodeID(node_id); //set node ID
   node.setName("Config"); //set name
   er_code = node.start();  //start node
   if(er_code < 0) {} //if error

‘node’ starts with ‘0’ code (OK).
Then I defined ‘p_man’ class directly: ( I hid code inside functions)

  //Params for Configuration Server
    static struct Params
        {
  	    unsigned freq = 1;
        } configuration;
   class : public uavcan::IParamManager
   {
  	 void getParamNameByIndex(Index index, Name& out_name) const override
  	         {
  	             if (index == 0) { out_name = "freq"; }
  	         }
  	         void assignParamValue(const Name& name, const Value& value) override{.....}
  	         void readParamValue(const Name& name, Value& out_value) const override{.....}
  	         int saveAllParams() override{ .....}
  	         int eraseAllParams() override{.....}
  	         void readParamDefaultMaxMin(const Name& name, Value& out_def,
  	                                     NumericValue& out_max, NumericValue& out_min) const override{.....}
   }p_man;

After this I wrote:

   uavcan::ParamServer server(node);
   er_code = server.start(&p_man);
   if(er_code < 0) {} //if error
   node.setRestartRequestHandler(&restart_handler);
   node.setModeOperational();
   //set vector for remote params
   std::vector<uavcan::protocol::param::GetSet::Response> remote_params;
   uavcan::protocol::param::GetSet::Request req;
   req.index=remote_params.size();
   auto result = performBlockingServiceCall<uavcan::protocol::param::GetSet>(node,remote_node_id,req);

Getting a vector size in req.index=remote_params.size() returns ‘0’; Is it true for this?
result.first now returns with ‘-1’
Also… Should node_id and remote_node_id must be different? When ‘remote_node_id==node_id’ I get ‘-2’. When ‘remote_node_id!=node_id’ I get ‘-1’.
I suspect that I defined node with something wrong…


(Pavel Kirienko) #10

Should node_id and remote_node_id must be different? When ‘remote_node_id==node_id’ I get ‘-2’.

Of course. You can’t send a request to your local node.

I don’t see where are you updating remote_params. Please post the code of both nodes here.

P.S. please format your listings properly; there is a button for that in the post editor: image


(Sergey F1987) #11

Ok. I read that I need two nodes: (1-configuration, 2-remote)
At first I init both od them (c_node - configurator, r_node - remote node):

  //....................................................
  int c_node_id=4;  //config node id
  auto& c_node = getNode(); //get node
  c_node.setNodeID(c_node_id); //set node ID
  c_node.setName("Config"); //set name
  er_code = c_node.start();  //start node
  if(er_code < 0) {...}
  //..................................
  int r_node_id=5;
  auto& r_node = getNode(); //get node
  r_node.setNodeID(r_node_id); //set node ID
  r_node.setName("Remote"); //set name
  er_code = r_node.start();  //start node
  if(er_code < 0) {...}
  //....................................................

Both starts with OK (e_code=0)
Then I define params for manager (hidden body for IParamManager, for reduce reply):

    static struct Params
        {
  	    unsigned freq = 1;
  	    unsigned amendment = 0;
        } configuration;
   class : public uavcan::IParamManager {....(functions, bla-bla-bla)...}p_manager;

Then I simply starts server for remote node (r_node). After I directly set to operational-mode both nodes:

 //Init and start config-server
   uavcan::ParamServer server(r_node);
   er_code = server.start(&p_manager);
   if(er_code < 0) {...}
  //restart and set remote node to operational-mode
   r_node.setRestartRequestHandler(&restart_handler);
   r_node.setModeOperational();
  //set config-node to operational-mode too
  c_node.setModeOperational();

It’s seems, they starts with OK (er_code=0)
And now I do:

   std::vector<uavcan::protocol::param::GetSet::Response> remote_params;
   uavcan::protocol::param::GetSet::Request req;
   req.index=remote_params.size();
   auto result = performBlockingServiceCall<uavcan::protocol::param::GetSet>(c_node,r_node_id,req);

result.first returns with -1
I define vector of Response-struct (labeled as ‘remote-params’) with default size (=0). I understood, that I need initialize remote_params somehow according to:

    static struct Params
        {
  	    unsigned freq = 1;
  	    unsigned amendment = 0;
        } configuration;

But I stiil confused, how I can do it.


(Pavel Kirienko) #12

Apparently, your nodes can’t communicate with each other. How your CAN bus is set up?


(Sergey F1987) #13

Oh… It seems, I begin understand my troubles. So… We can build net with one configuration node and some remote nodes? Right? But I tried to unite configuration-node and remote-node in one global node. But i see, that is unavailable. ?! I wanted to regulate params for my remote node as it was also configuration node.


(Pavel Kirienko) #14

UAVCAN does not define any means of node-local communication (although it doesn’t really prohibit that either; it is just omitted from the spec). That means that you can’t send a request, or a message, to your own local node – the transfer would just disappear into nowhere. You can only communicate with remote nodes.


(Sergey F1987) #15

Thanks. I check this. But now I have another question. So… I starts my remote node. Configurator-node sends a some value to remote node (to me) for parameter named as ‘freq’. How can I read this (get received value) inside remote-node? I’m able to read data through basic HAL functions for CAN periph. But now libuavcan installed. Are this steps will right?
(This Remote-node is already started with OK):

  uavcan::protocol::param::GetSet::Response resp;
  uavcan::protocol::param::GetSet::Request req;
  req.index=1;
  req.name="freq";
  req.value=resp.value;
  //get result of service
  auto result = performBlockingServiceCall<uavcan::protocol::param::GetSet>(node,node_id,req);
  //get frequency from params
  frequency=result.second.value.to<uavcan::protocol::param::Value::Tag::integer_value>();

I need get value from ‘freq’ param inside this remote-node (value was send from ‘configurator’ before with OK)


(Pavel Kirienko) #16

You should use methods as and is instead of to:

/**
 * Whether the union is set to the given type.
 * Access by tag; this will work even if there are non-unique types within the union.
 */
bool is(typename Tag::Type x) const { return typename Tag::Type(_tag_) == x; }

/**
 * If the union is currently set to the type T, returns pointer to the appropriate field.
 * If the union is set to another type, returns null pointer.
 */
template <typename Tag::Type T>
inline const typename TagToType<T>::StorageType* as() const;

/**
 * Switches the union to the given type and returns a mutable reference to the appropriate field.
 * If the previous type was different, a default constructor will be called first.
 */
template <typename Tag::Type T>
inline typename TagToType<T>::StorageType& to();