Homepage GitHub

Uavcan Service call response request is empty except for the boolean fields

I am using uavcan to communicate between an IMX6 and stm32f4. stm32f4 has a configuration server which updates some parameters locally when a request is made from the IMX6::ros node. Here is the code from the IMX6 side of things:

void motorController::configCallback(const robotics_msgs::Config& conf)	{
	if(conf.enableControl)
	{
		uavcan::control::config::Config::Request req;
		req.enableControl = true;
		req.encoderTicksPerRev = params.maxEncoderTicks;
		req.maxRpm = params.maxrpmMotor;
		req.gearRatio = params.gearRatio;

		const int res = configClient.call(this->nParams.config_server_ID, req);
		if(res < 0)
		{
			ROS_INFO("config Client call failed\n");
		}
		else
			ROS_INFO("config call successful\n");
	}
}

on the stm32 side:

const int config_res = configServer.start([&](const uavcan::ReceivedDataStructure<uavcan::control::config::Config::Request>& req,
				uavcan::control::config::Config::Response& resp)
{
	if(req.enableControl)
	{
	  if(!paramsInited)
	   {
	      staticParams.maxRPM = req.maxRpm;
	      staticParams.gearRatio = req.gearRatio;
	      staticParams.maxEncoderTicks = req.encoderTicksPerRev;
	      paramsInited = true;
              resp.configApplied = true;
	  }
	  if(!driverInited)
	  {
	     driver.init(staticParams.maxRPM,staticParams.gearRatio);
	     driverInited=true;
	     resp.configApplied = true;
	  }
	}
	else
	{
	   resp.configApplied = false;
	}	
});

	
if(config_res < 0)
{
   sys::debug(Debug_Level::Error,"Failed to start config Server\r\n");
   uavcan_thd.stop();
}

after a successful service call. The boolean fields are properly initialized but the other fields are ‘0’. I have checked it with other service calls as well by making the stm32f4 a client and IMX6 a server. Below is the uavcan message definition

bool enableControl
uavcan.control.RpmPID Pid 

uint32 encoderTicksPerRev
uint16 encoderPubHz
uint16 controlLoopHz

uint8 maxRpm
uint8 gearRatio
uint8 accLimit

uint8  MODE_OPENLOOP = 0
uint8  MODE_CLOSEDLOOP = 1
uint8  mode

---

bool configApplied

Any suggestions on what might be wrong?

My understanding is that the boolean field you are referring to is enableControl? I see no other boolean fields in the request schema.

You seem to be using the free store (heap) in your STM32 code indirectly through the lambda closure. Probably a bad idea unless you really understand how it works and what the trade-offs are. You also seem to be running a multi-threaded environment (judging by uavcan_thd.stop()) which makes it a minefield unless the proper precautions have been taken – I assume they weren’t because you didn’t mention that.

I suggest making sure that the firmware is sound before proceeding further.

Hi Pavel,

Thank you for the thorough response.

In regards to the usage of free store in the code sample pasted above. I always thought of c++ lambda closures as stack-allocated objects and if i’m capturing something by reference “staticParams” here then it is simply a reference member variable of the lambda object. And the lambda lives as long as the scope in which it was declared i.e uavcan_thd::main(). Since staticParams is a member variable of the class uavcan_thd it has a longer lifetime than that of the closure. I’ve cross-checked and the closure seems to be static allocated on the uavcan_thd stack. Regarding multi-threading, currently i have disabled all other threads except the uavcan node and the chibios idle thread.

reference : https://stackoverflow.com/questions/12202656/c11-lambda-implementation-and-memory-model

This is the output when i query the “uavcan_data_type”::Request object in gdb:

(const uavcan::ReceivedDataStructure<uavcan::control::config::Config_::Request_<0> > &) @0x2000c9b0: {<uavcan::control::config::Config_::Request_<0>> = {static MODE_OPENLOOP = <optimized out>,
    static MODE_CLOSEDLOOP = <optimized out>, enableControl = true, Pid = {kp = 0, ki = 0, kd = 0, ilimit = 0}, encoderTicksPerRev = 0, encoderPubHz = 0, controlLoopHz = 0, maxRpm = 0 '\000', gearRatio = 0 '\000', accLimit = 0 '\000',
    mode = 0 '\000'}, <uavcan::Noncopyable> = {<No data fields>}, _transfer_ = 0x2000ca08 <can::imuNode+6024>}

only the boolean variable has been initialized to its intended value

Re lambdas: a heap allocation may occur when your closure is passed into start(std::function<...>) of the server. At least GCC v7 with C++14 seems to be doing that at least occasionally; the standard does not prohibit that. I would recommend to avoid closures completely unless you can tolerate dynamic storage allocation.

I don’t know why your object is not being assigned correctly, sorry. The available context is insufficient and I don’t think it is related to Libuavcan anyway.

Thank you @pavel.kirienko. I will remove all the lambda’s and check if the problem persists.