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.
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>();
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.
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)
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’
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…
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:
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.
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.
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)
/**
* 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();