18 #include <condition_variable> 21 #include <mavros_msgs/ParamSet.h> 22 #include <mavros_msgs/ParamGet.h> 23 #include <mavros_msgs/ParamPull.h> 24 #include <mavros_msgs/ParamPush.h> 25 #include <mavros_msgs/Param.h> 28 namespace std_plugins {
51 using MT = mavlink::common::MAV_PARAM_TYPE;
60 void set_value(mavlink::common::msg::PARAM_VALUE &pmsg)
62 mavlink::mavlink_param_union_t uv;
63 uv.param_float = pmsg.param_value;
69 switch (pmsg.param_type) {
87 int_tmp = uv.param_int8;
88 param_value = int_tmp;
91 int_tmp = uv.param_uint8;
92 param_value = int_tmp;
95 int_tmp = uv.param_int16;
96 param_value = int_tmp;
99 int_tmp = uv.param_uint16;
100 param_value = int_tmp;
103 int_tmp = uv.param_int32;
104 param_value = int_tmp;
107 int_tmp = uv.param_uint32;
108 param_value = int_tmp;
111 float_tmp = uv.param_float;
112 param_value = float_tmp;
117 ROS_WARN_NAMED(
"param",
"PM: Unsupported param %.16s (%u/%u) type: %u",
118 pmsg.param_id.data(), pmsg.param_index, pmsg.param_count, pmsg.param_type);
131 switch (pmsg.param_type) {
141 int_tmp = pmsg.param_value;
142 param_value = int_tmp;
145 int_tmp = pmsg.param_value;
146 param_value = int_tmp;
149 int_tmp = pmsg.param_value;
150 param_value = int_tmp;
153 int_tmp = pmsg.param_value;
154 param_value = int_tmp;
157 int_tmp = pmsg.param_value;
158 param_value = int_tmp;
161 int_tmp = pmsg.param_value;
162 param_value = int_tmp;
165 float_tmp = pmsg.param_value;
166 param_value = float_tmp;
171 ROS_WARN_NAMED(
"param",
"PM: Unsupported param %.16s (%u/%u) type: %u",
172 pmsg.param_id.data(), pmsg.param_index, pmsg.param_count, pmsg.param_type);
183 mavlink::mavlink_param_union_t uv;
188 switch (param_value.
getType()) {
208 uv.param_int32 =
static_cast<int32_t
>(
param_value);
221 ret.param_value = uv.param_float;
232 switch (param_value.
getType()) {
241 ret.param_value =
static_cast<bool &
>(
param_value);
245 ret.param_value =
static_cast<int32_t &
>(
param_value);
249 ret.param_value =
static_cast<double &
>(
param_value);
266 switch (param_value.
getType()) {
285 return static_cast<double>(param_value);
298 mavros_msgs::Param
msg;
317 return param_id ==
"SYSID_SW_MREV" ||
318 param_id ==
"SYS_NUM_RESETS" ||
319 param_id ==
"ARSPD_OFFSET" ||
320 param_id ==
"GND_ABS_PRESS" ||
321 param_id ==
"GND_TEMP" ||
322 param_id ==
"CMD_TOTAL" ||
323 param_id ==
"CMD_INDEX" ||
324 param_id ==
"LOG_LASTFILE" ||
325 param_id ==
"FENCE_TOTAL" ||
326 param_id ==
"FORMAT_VERSION";
338 retries_remaining(_rem),
346 std::condition_variable
ack;
358 param_state(
PR::IDLE),
360 RETRIES_COUNT(_RETRIES_COUNT),
361 param_rx_retries(RETRIES_COUNT),
362 BOOTUP_TIME_DT(BOOTUP_TIME_MS / 1000.0),
363 LIST_TIMEOUT_DT(LIST_TIMEOUT_MS / 1000.0),
364 PARAM_TIMEOUT_DT(PARAM_TIMEOUT_MS / 1000.0)
369 PluginBase::initialize(uas_);
376 param_value_pub = param_nh.advertise<mavros_msgs::Param>(
"param_value", 100);
379 shedule_timer.stop();
381 timeout_timer.stop();
382 enable_connection_cb();
409 static constexpr
int BOOTUP_TIME_MS = 10000;
410 static constexpr
int PARAM_TIMEOUT_MS = 1000;
411 static constexpr
int LIST_TIMEOUT_MS = 30000;
412 static constexpr
int _RETRIES_COUNT = 3;
439 void handle_param_value(
const mavlink::mavlink_message_t *msg, mavlink::common::msg::PARAM_VALUE &pmsg)
446 auto param_it = parameters.find(
param_id);
447 if (param_it != parameters.end()) {
449 auto &p = param_it->second;
451 if (m_uas->is_ardupilotmega())
452 p.set_value_apm_quirk(pmsg);
457 auto set_it = set_parameters.find(
param_id);
458 if (set_it != set_parameters.end()) {
459 set_it->second->ack.notify_all();
462 param_value_pub.
publish(p.to_msg());
465 ((p.param_index != pmsg.param_index &&
466 pmsg.param_index != UINT16_MAX) ||
467 p.param_count != pmsg.param_count),
469 "PR: Param " << p.to_string() <<
" different index: " << pmsg.param_index <<
"/" << pmsg.param_count);
476 p.param_index = pmsg.param_index;
477 p.param_count = pmsg.param_count;
479 if (m_uas->is_ardupilotmega())
480 p.set_value_apm_quirk(pmsg);
486 param_value_pub.
publish(p.to_msg());
491 if (param_state == PR::RXLIST || param_state == PR::RXPARAM || param_state == PR::RXPARAM_TIMEDOUT) {
494 if (param_state == PR::RXLIST) {
495 param_count = pmsg.param_count;
496 param_state = PR::RXPARAM;
498 parameters_missing_idx.clear();
499 if (param_count != UINT16_MAX) {
503 parameters_missing_idx.push_back(idx);
506 ROS_WARN_NAMED(
"param",
"PR: FCU does not know index for first element! " 507 "Param list may be truncated.");
512 bool it_is_first_requested = parameters_missing_idx.front() == pmsg.param_index;
515 parameters_missing_idx.remove(pmsg.param_index);
518 if (it_is_first_requested) {
519 ROS_DEBUG_NAMED(
"param",
"PR: got a value of a requested param idx=%u, " 520 "resetting retries count", pmsg.param_index);
521 param_rx_retries = RETRIES_COUNT;
522 }
else if (param_state == PR::RXPARAM_TIMEDOUT) {
523 ROS_INFO_NAMED(
"param",
"PR: got an unsolicited param value idx=%u, " 524 "not resetting retries count %zu", pmsg.param_index, param_rx_retries);
527 restart_timeout_timer();
530 if (parameters_missing_idx.empty()) {
531 ssize_t missed = param_count - parameters.size();
534 "PR: parameters list received, but %zd parametars are missed",
537 list_receiving.notify_all();
538 }
else if (param_state == PR::RXPARAM_TIMEDOUT) {
539 uint16_t first_miss_idx = parameters_missing_idx.front();
540 ROS_DEBUG_NAMED(
"param",
"PR: requesting next timed out parameter idx=%u", first_miss_idx);
541 param_request_read(
"", first_miss_idx);
552 mavlink::common::msg::PARAM_REQUEST_LIST rql{};
553 m_uas->msg_set_target(rql);
555 UAS_FCU(m_uas)->send_message_ignore_drop(rql);
562 ROS_DEBUG_NAMED(
"param",
"PR:m: request '%s', idx %d",
id.c_str(), index);
564 mavlink::common::msg::PARAM_REQUEST_READ rqr{};
565 m_uas->msg_set_target(rqr);
566 rqr.param_index = index;
572 UAS_FCU(m_uas)->send_message_ignore_drop(rqr);
580 auto ps = ([
this, ¶m]() -> mavlink::common::msg::PARAM_SET {
581 if (m_uas->is_ardupilotmega())
587 m_uas->msg_set_target(ps);
589 UAS_FCU(m_uas)->send_message_ignore_drop(ps);
598 shedule_pull(BOOTUP_TIME_DT);
601 shedule_timer.
stop();
607 shedule_timer.
stop();
609 shedule_timer.
start();
615 if (param_state != PR::IDLE) {
618 shedule_pull(BOOTUP_TIME_DT);
622 param_state = PR::RXLIST;
623 param_rx_retries = RETRIES_COUNT;
626 restart_timeout_timer();
627 param_request_list();
633 if (param_state == PR::RXLIST && param_rx_retries > 0) {
635 ROS_WARN_NAMED(
"param",
"PR: request list timeout, retries left %zu", param_rx_retries);
637 restart_timeout_timer();
638 param_request_list();
640 else if (param_state == PR::RXPARAM || param_state == PR::RXPARAM_TIMEDOUT) {
641 if (parameters_missing_idx.empty()) {
642 ROS_WARN_NAMED(
"param",
"PR: missing list is clear, but we in RXPARAM state, " 643 "maybe last rerequest fails. Params missed: %zd",
644 param_count - parameters.size());
646 list_receiving.notify_all();
650 param_state = PR::RXPARAM_TIMEDOUT;
651 uint16_t first_miss_idx = parameters_missing_idx.front();
652 if (param_rx_retries > 0) {
654 ROS_WARN_NAMED(
"param",
"PR: request param #%u timeout, retries left %zu, and %zu params still missing",
655 first_miss_idx, param_rx_retries, parameters_missing_idx.size());
656 restart_timeout_timer();
657 param_request_read(
"", first_miss_idx);
660 ROS_ERROR_NAMED(
"param",
"PR: request param #%u completely missing.", first_miss_idx);
661 parameters_missing_idx.pop_front();
662 restart_timeout_timer();
663 if (!parameters_missing_idx.empty()) {
664 param_rx_retries = RETRIES_COUNT;
665 first_miss_idx = parameters_missing_idx.front();
667 ROS_WARN_NAMED(
"param",
"PR: %zu params still missing, trying to request next: #%u",
668 parameters_missing_idx.size(), first_miss_idx);
669 param_request_read(
"", first_miss_idx);
673 else if (param_state == PR::TXPARAM) {
674 auto it = set_parameters.begin();
675 if (it == set_parameters.end()) {
681 if (it->second->retries_remaining > 0) {
682 it->second->retries_remaining--;
683 ROS_WARN_NAMED(
"param",
"PR: Resend param set for %s, retries left %zu",
684 it->second->param.param_id.c_str(),
685 it->second->retries_remaining);
686 restart_timeout_timer();
691 it->second->param.param_id.c_str());
692 it->second->is_timedout =
true;
693 it->second->ack.notify_all();
704 timeout_timer.
stop();
705 timeout_timer.
start();
710 param_state = PR::IDLE;
711 timeout_timer.
stop();
716 std::unique_lock<std::mutex> lock(list_cond_mutex);
718 return list_receiving.wait_for(lock, std::chrono::nanoseconds(LIST_TIMEOUT_DT.
toNSec()))
719 == std::cv_status::no_timeout
725 std::unique_lock<std::mutex> lock(opt->cond_mutex);
727 return opt->ack.wait_for(lock, std::chrono::nanoseconds(PARAM_TIMEOUT_DT.
toNSec()) * (RETRIES_COUNT + 2))
728 == std::cv_status::no_timeout
729 && !opt->is_timedout;
737 auto opt = std::make_shared<ParamSetOpt>(param, RETRIES_COUNT);
738 set_parameters[param.param_id] = opt;
740 param_state = PR::TXPARAM;
741 restart_timeout_timer();
745 bool is_not_timeout = wait_param_set_ack_for(opt);
749 set_parameters.erase(param.param_id);
752 return is_not_timeout;
758 if (m_uas->is_px4() && p.
param_id ==
"_HASH_CHECK") {
760 ROS_INFO_NAMED(
"param",
"PR: PX4 parameter _HASH_CHECK ignored: 0x%8x", static_cast<int32_t>(v));
774 bool pull_cb(mavros_msgs::ParamPull::Request &req,
775 mavros_msgs::ParamPull::Response &res)
779 if ((param_state == PR::IDLE && parameters.empty())
786 param_state = PR::RXLIST;
787 param_rx_retries = RETRIES_COUNT;
790 shedule_timer.
stop();
791 restart_timeout_timer();
792 param_request_list();
795 res.success = wait_fetch_all();
797 else if (param_state == PR::RXLIST || param_state == PR::RXPARAM || param_state == PR::RXPARAM_TIMEDOUT) {
799 res.success = wait_fetch_all();
807 res.param_received = parameters.size();
809 for (
auto &p : parameters) {
811 rosparam_set_allowed(p.second);
822 bool push_cb(mavros_msgs::ParamPush::Request &req,
823 mavros_msgs::ParamPush::Response &res)
826 if (!param_nh.
getParam(
"", param_dict))
832 for (
auto &
param : param_dict) {
839 auto param_it = parameters.find(
param.first);
840 if (param_it != parameters.end()) {
842 auto to_send = param_it->second;
845 to_send.param_value =
param.second;
848 bool set_res = send_param_set_and_wait(to_send);
860 res.param_transfered = tx_count;
869 bool set_cb(mavros_msgs::ParamSet::Request &req,
870 mavros_msgs::ParamSet::Response &res)
874 if (param_state == PR::RXLIST || param_state == PR::RXPARAM || param_state == PR::RXPARAM_TIMEDOUT) {
879 auto param_it = parameters.find(req.param_id);
880 if (param_it != parameters.end()) {
881 auto to_send = param_it->second;
884 if (req.value.integer != 0)
885 to_send.param_value =
static_cast<int>(req.value.integer);
886 else if (req.value.real != 0.0)
887 to_send.param_value = req.value.real;
889 to_send.param_value = 0;
892 res.success = send_param_set_and_wait(to_send);
895 res.value.integer = param_it->second.to_integer();
896 res.value.real = param_it->second.to_real();
899 rosparam_set_allowed(param_it->second);
913 bool get_cb(mavros_msgs::ParamGet::Request &req,
914 mavros_msgs::ParamGet::Response &res)
918 auto param_it = parameters.find(req.param_id);
919 if (param_it != parameters.end()) {
922 res.value.integer = param_it->second.to_integer();
923 res.value.real = param_it->second.to_real();
MAVROS Plugin base class.
#define ROS_WARN_COND_NAMED(cond, name,...)
std::unique_lock< std::recursive_mutex > unique_lock
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val)
#define ROS_WARN_STREAM_COND_NAMED(cond, name, args)
#define ROS_INFO_NAMED(name,...)
#define ROS_INFO_COND_NAMED(cond, name,...)
#define ROS_DEBUG_STREAM_NAMED(name, args)
std::string format(const std::string &fmt, Args...args)
void publish(const boost::shared_ptr< M > &message) const
#define ROS_ERROR_STREAM_NAMED(name, args)
void timeout_cb(const ros::TimerEvent &event)
#define ROS_WARN_NAMED(name,...)
std::condition_variable ack
def param_set(param_id, value)
std::string to_string() const
std::condition_variable list_receiving
void set_value_apm_quirk(mavlink::common::msg::PARAM_VALUE &pmsg)
void initialize(UAS &uas_)
Plugin initializer.
ros::Publisher param_value_pub
void setPeriod(const Duration &period, bool reset=true)
const ros::Duration PARAM_TIMEOUT_DT
mavlink::common::msg::PARAM_SET PARAM_SET
bool wait_param_set_ack_for(std::shared_ptr< ParamSetOpt > opt)
PARAM_SET to_param_set()
Make PARAM_SET message. Set target ids manually!
Subscriptions get_subscriptions()
Return vector of MAVLink message subscriptions (handlers)
void shedule_cb(const ros::TimerEvent &event)
static bool check_exclude_param_id(std::string param_id)
void set_value(mavlink::common::msg::PARAM_VALUE &pmsg)
mavros_msgs::Param to_msg()
Type const & getType() const
void restart_timeout_timer()
std::mutex list_cond_mutex
bool set_cb(mavros_msgs::ParamSet::Request &req, mavros_msgs::ParamSet::Response &res)
sets parameter value ~param/set
#define ROS_DEBUG_NAMED(name,...)
PARAM_SET to_param_set_apm_qurk()
Make PARAM_SET message. Set target ids manually!
Parameter manipulation plugin.
std::string toXml() const
void param_request_read(std::string id, int16_t index=-1)
mavlink::common::MAV_PARAM_TYPE MT
ros::ServiceServer push_srv
bool send_param_set_and_wait(Parameter ¶m)
#define UAS_FCU(uasobjptr)
helper accessor to FCU link interface
ros::Timer shedule_timer
for startup shedule fetch
ParamSetOpt(Parameter &_p, size_t _rem)
void param_set(Parameter ¶m)
const ros::Duration BOOTUP_TIME_DT
bool get_cb(mavros_msgs::ParamGet::Request &req, mavros_msgs::ParamGet::Response &res)
get parameter ~param/get
bool pull_cb(mavros_msgs::ParamPull::Request &req, mavros_msgs::ParamPull::Response &res)
fetches all parameters from device ~param/pull
void param_request_list()
void shedule_pull(const ros::Duration &dt)
ros::Timer timeout_timer
for timeout resend
const ros::Duration LIST_TIMEOUT_DT
ros::ServiceServer pull_srv
std::vector< HandlerInfo > Subscriptions
Subscriptions vector.
Parameter set transaction data.
bool getParam(const std::string &key, std::string &s) const
void set_string(std::array< char, _N > &a, const std::string &s)
std::unordered_map< std::string, std::shared_ptr< ParamSetOpt > > set_parameters
bool push_cb(mavros_msgs::ParamPush::Request &req, mavros_msgs::ParamPush::Response &res)
push all parameter value to device ~param/push
std::unordered_map< std::string, Parameter > parameters
#define ROS_ERROR_NAMED(name,...)
void handle_param_value(const mavlink::mavlink_message_t *msg, mavlink::common::msg::PARAM_VALUE &pmsg)
ros::ServiceServer set_srv
std::lock_guard< std::recursive_mutex > lock_guard
ros::ServiceServer get_srv
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
void connection_cb(bool connected) override
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const
std::string to_string(const std::array< char, _N > &a)
std::list< uint16_t > parameters_missing_idx
std::recursive_mutex mutex
constexpr std::underlying_type< _T >::type enum_value(_T e)
std::recursive_mutex mutex
#define ROS_WARN_STREAM_NAMED(name, args)
bool rosparam_set_allowed(const Parameter &p)
Set ROS param only if name is good.