From cc7ee03e1bf2f76195902991c17d0a7f6e73443c Mon Sep 17 00:00:00 2001 From: pmlab <lfreixas@iri.upc.edu> Date: Wed, 10 Oct 2018 16:46:55 +0200 Subject: [PATCH] added use robot_localization node for ekf --- include/htc_vive_tracker_alg.h | 1 + launch/htc_vive_main.launch | 9 + launch/publish_wam_chaperone_link.launch | 3 +- launch/wam_follow_device.launch | 8 +- params/ekf_htcvive.yaml | 251 +++++++++++++++++++++++ src/htc_vive_tracker_alg_node.cpp | 18 +- 6 files changed, 282 insertions(+), 8 deletions(-) create mode 100644 launch/htc_vive_main.launch create mode 100644 params/ekf_htcvive.yaml diff --git a/include/htc_vive_tracker_alg.h b/include/htc_vive_tracker_alg.h index 5a922b7..eb5dd3d 100644 --- a/include/htc_vive_tracker_alg.h +++ b/include/htc_vive_tracker_alg.h @@ -145,6 +145,7 @@ class HtcViveTrackerAlgorithm bool TriggerHapticPulse(const std::string & device_name, uint32_t strength); + //TODO decide if this functions will return orientation as given or always the same geometry_msgs::PoseStamped PoseFromTF(const tf::StampedTransform & stamped_transform); // the driver parameters diff --git a/launch/htc_vive_main.launch b/launch/htc_vive_main.launch new file mode 100644 index 0000000..282f751 --- /dev/null +++ b/launch/htc_vive_main.launch @@ -0,0 +1,9 @@ +<launch> + <arg name="target_frame" default="tracker_1" /> + <node pkg="iri_htc_vive_tracker" + type = "iri_htc_vive_tracker" + name = "iri_htc_vive_tracker" + output = "screen"> + <param name="~target_frame_name" type="string" value="$(arg target_frame)"/> + </node> +</launch> diff --git a/launch/publish_wam_chaperone_link.launch b/launch/publish_wam_chaperone_link.launch index 1f607fe..b09a620 100644 --- a/launch/publish_wam_chaperone_link.launch +++ b/launch/publish_wam_chaperone_link.launch @@ -22,8 +22,7 @@ name = "iri_htc_vive_tracker" output = "screen"> <param name="~target_frame_name" type="string" value="$(arg target_frame)"/> - <remap from="~new_pose" to="/iri_wam/pose_surface"/> - <remap from="~vo" to="/vo"/> </node> + </launch> diff --git a/launch/wam_follow_device.launch b/launch/wam_follow_device.launch index 1a7648b..0ab1da7 100644 --- a/launch/wam_follow_device.launch +++ b/launch/wam_follow_device.launch @@ -6,9 +6,9 @@ <arg name="target_frame" value ="$(arg device)"/> </include> - <include file="$(find robot_pose_ekf)/robot_pose_ekf.launch"/> - <param name="robot_pose_ekf/odom_used" value="false"/> - <param name="robot_pose_ekf/imu_used" value="false"/> - <param name="robot_pose_ekf/vo_used" value="false"/> + + <node pkg="robot_localization" type="ekf_localization_node" name="ekf_se" clear_params="true"> + <rosparam command="load" file="$(find iri_htc_vive_tracker)/params/ekf_htcvive.yaml" /> + </node> </launch> diff --git a/params/ekf_htcvive.yaml b/params/ekf_htcvive.yaml new file mode 100644 index 0000000..74e0d10 --- /dev/null +++ b/params/ekf_htcvive.yaml @@ -0,0 +1,251 @@ +# The frequency, in Hz, at which the filter will output a position estimate. Note that the filter will not begin +# computation until it receives at least one message from one of the inputs. It will then run continuously at the +# frequency specified here, regardless of whether it receives more measurements. Defaults to 30 if unspecified. +frequency: 30 + +# The period, in seconds, after which we consider a sensor to have timed out. In this event, we carry out a predict +# cycle on the EKF without correcting it. This parameter can be thought of as the minimum frequency with which the +# filter will generate new output. Defaults to 1 / frequency if not specified. +sensor_timeout: 0.1 + +# ekf_localization_node and ukf_localization_node both use a 3D omnidirectional motion model. If this parameter is +# set to true, no 3D information will be used in your state estimate. Use this if you are operating in a planar +# environment and want to ignore the effect of small variations in the ground plane that might otherwise be detected +# by, for example, an IMU. Defaults to false if unspecified. +two_d_mode: false + +# Use this parameter to provide an offset to the transform generated by ekf_localization_node. This can be used for +# future dating the transform, which is required for interaction with some other packages. Defaults to 0.0 if +# unspecified. +transform_time_offset: 0.0 + +# Use this parameter to provide specify how long the tf listener should wait for a transform to become available. +# Defaults to 0.0 if unspecified. +transform_timeout: 0.0 + +# If you're having trouble, try setting this to true, and then echo the /diagnostics_agg topic to see if the node is +# unhappy with any settings or data. +print_diagnostics: true + +# Debug settings. Not for the faint of heart. Outputs a ludicrous amount of information to the file specified by +# debug_out_file. I hope you like matrices! Please note that setting this to true will have strongly deleterious +# effects on the performance of the node. Defaults to false if unspecified. +debug: false + +# Defaults to "robot_localization_debug.txt" if unspecified. Please specify the full path. +debug_out_file: /path/to/debug/file.txt + +# Whether to broadcast the transformation over the /tf topic. Defaults to true if unspecified. +publish_tf: true + +# Whether to publish the acceleration state. Defaults to false if unspecified. +publish_acceleration: false + +# REP-105 (http://www.ros.org/reps/rep-0105.html) specifies four principal coordinate frames: base_link, odom, map, and +# earth. base_link is the coordinate frame that is affixed to the robot. Both odom and map are world-fixed frames. +# The robot's position in the odom frame will drift over time, but is accurate in the short term and should be +# continuous. The odom frame is therefore the best frame for executing local motion plans. The map frame, like the odom +# frame, is a world-fixed coordinate frame, and while it contains the most globally accurate position estimate for your +# robot, it is subject to discrete jumps, e.g., due to the fusion of GPS data or a correction from a map-based +# localization node. The earth frame is used to relate multiple map frames by giving them a common reference frame. +# ekf_localization_node and ukf_localization_node are not concerned with the earth frame. +# Here is how to use the following settings: +# 1. Set the map_frame, odom_frame, and base_link frames to the appropriate frame names for your system. +# 1a. If your system does not have a map_frame, just remove it, and make sure "world_frame" is set to the value of +# odom_frame. +# 2. If you are fusing continuous position data such as wheel encoder odometry, visual odometry, or IMU data, set +# "world_frame" to your odom_frame value. This is the default behavior for robot_localization's state estimation nodes. +# 3. If you are fusing global absolute position data that is subject to discrete jumps (e.g., GPS or position updates +# from landmark observations) then: +# 3a. Set your "world_frame" to your map_frame value +# 3b. MAKE SURE something else is generating the odom->base_link transform. Note that this can even be another state +# estimation node from robot_localization! However, that instance should *not* fuse the global data. +map_frame: map # Defaults to "map" if unspecified +odom_frame: odom # Defaults to "odom" if unspecified +base_link_frame: iri_wam_link_base # Defaults to "base_link" if unspecified +world_frame: odom # Defaults to the value of odom_frame if unspecified + +# The filter accepts an arbitrary number of inputs from each input message type (nav_msgs/Odometry, +# geometry_msgs/PoseWithCovarianceStamped, geometry_msgs/TwistWithCovarianceStamped, +# sensor_msgs/Imu). To add an input, simply append the next number in the sequence to its "base" name, e.g., odom0, +# odom1, twist0, twist1, imu0, imu1, imu2, etc. The value should be the topic name. These parameters obviously have no +# default values, and must be specified. +odom0: iri_htc_vive_tracker/vo + +# Each sensor reading updates some or all of the filter's state. These options give you greater control over which +# values from each measurement are fed to the filter. For example, if you have an odometry message as input, but only +# want to use its Z position value, then set the entire vector to false, except for the third entry. The order of the +# values is x, y, z, roll, pitch, yaw, vx, vy, vz, vroll, vpitch, vyaw, ax, ay, az. Note that not some message types +# do not provide some of the state variables estimated by the filter. For example, a TwistWithCovarianceStamped message +# has no pose information, so the first six values would be meaningless in that case. Each vector defaults to all false +# if unspecified, effectively making this parameter required for each sensor. +odom0_config: [true, true, true, + true, true, true, + true, true, true, + true, true, true, + true, true, true] + +# If you have high-frequency data or are running with a low frequency parameter value, then you may want to increase +# the size of the subscription queue so that more measurements are fused. +odom0_queue_size: 2 + +# [ADVANCED] Large messages in ROS can exhibit strange behavior when they arrive at a high frequency. This is a result +# of Nagle's algorithm. This option tells the ROS subscriber to use the tcpNoDelay option, which disables Nagle's +# algorithm. +odom0_nodelay: false + +# [ADVANCED] When measuring one pose variable with two sensors, a situation can arise in which both sensors under- +# report their covariances. This can lead to the filter rapidly jumping back and forth between each measurement as they +# arrive. In these cases, it often makes sense to (a) correct the measurement covariances, or (b) if velocity is also +# measured by one of the sensors, let one sensor measure pose, and the other velocity. However, doing (a) or (b) isn't +# always feasible, and so we expose the differential parameter. When differential mode is enabled, all absolute pose +# data is converted to velocity data by differentiating the absolute pose measurements. These velocities are then +# integrated as usual. NOTE: this only applies to sensors that provide pose measurements; setting differential to true +# for twist measurements has no effect. +odom0_differential: false + +# [ADVANCED] When the node starts, if this parameter is true, then the first measurement is treated as a "zero point" +# for all future measurements. While you can achieve the same effect with the differential paremeter, the key +# difference is that the relative parameter doesn't cause the measurement to be converted to a velocity before +# integrating it. If you simply want your measurements to start at 0 for a given sensor, set this to true. +odom0_relative: false + +# [ADVANCED] If your data is subject to outliers, use these threshold settings, expressed as Mahalanobis distances, to +# control how far away from the current vehicle state a sensor measurement is permitted to be. Each defaults to +# numeric_limits<double>::max() if unspecified. It is strongly recommended that these parameters be removed if not +# required. Data is specified at the level of pose and twist variables, rather than for each variable in isolation. +# For messages that have both pose and twist data, the parameter specifies to which part of the message we are applying +# the thresholds. +odom0_pose_rejection_threshold: 5 +odom0_twist_rejection_threshold: 1 + +# Further input parameter examples +odom1: example/another_odom +odom1_config: [false, false, false, + false, false, false, + false, false, false, + false, false, false, + false, false, false] +odom1_differential: false +odom1_relative: true +odom1_queue_size: 2 +odom1_pose_rejection_threshold: 2 +odom1_twist_rejection_threshold: 0.2 +odom1_nodelay: false + +pose0: example/pose +pose0_config: [false, false, false, + false, false, false, + false, false, false, + false, false, false, + false, false, false] +pose0_differential: true +pose0_relative: false +pose0_queue_size: 5 +pose0_rejection_threshold: 2 # Note the difference in parameter name +pose0_nodelay: false + +twist0: example/twist +twist0_config: [false, false, false, + false, false, false, + false, false, false, + false, false, false, + false, false, false] +twist0_queue_size: 3 +twist0_rejection_threshold: 2 +twist0_nodelay: false + +imu0: example/imu +imu0_config: [false, false, false, + false, false, false, + false, false, false, + false, false, false, + false, false, false] +imu0_nodelay: false +imu0_differential: false +imu0_relative: true +imu0_queue_size: 5 +imu0_pose_rejection_threshold: 0.8 # Note the difference in parameter names +imu0_twist_rejection_threshold: 0.8 # +imu0_linear_acceleration_rejection_threshold: 0.8 # + +# [ADVANCED] Some IMUs automatically remove acceleration due to gravity, and others don't. If yours doesn't, please set +# this to true, and *make sure* your data conforms to REP-103, specifically, that the data is in ENU frame. +imu0_remove_gravitational_acceleration: true + +# [ADVANCED] The EKF and UKF models follow a standard predict/correct cycle. During prediction, if there is no +# acceleration reference, the velocity at time t+1 is simply predicted to be the same as the velocity at time t. During +# correction, this predicted value is fused with the measured value to produce the new velocity estimate. This can be +# problematic, as the final velocity will effectively be a weighted average of the old velocity and the new one. When +# this velocity is the integrated into a new pose, the result can be sluggish covergence. This effect is especially +# noticeable with LIDAR data during rotations. To get around it, users can try inflating the process_noise_covariance +# for the velocity variable in question, or decrease the variance of the variable in question in the measurement +# itself. In addition, users can also take advantage of the control command being issued to the robot at the time we +# make the prediction. If control is used, it will get converted into an acceleration term, which will be used during +# predicition. Note that if an acceleration measurement for the variable in question is available from one of the +# inputs, the control term will be ignored. +# Whether or not we use the control input during predicition. Defaults to false. +use_control: true +# Whether the input (assumed to be cmd_vel) is a geometry_msgs/Twist or geometry_msgs/TwistStamped message. Defaults to +# false. +stamped_control: false +# The last issued control command will be used in prediction for this period. Defaults to 0.2. +control_timeout: 0.2 +# Which velocities are being controlled. Order is vx, vy, vz, vroll, vpitch, vyaw. +control_config: [true, false, false, false, false, true] +# Places limits on how large the acceleration term will be. Should match your robot's kinematics. +acceleration_limits: [1.3, 0.0, 0.0, 0.0, 0.0, 3.4] +# Acceleration and deceleration limits are not always the same for robots. +deceleration_limits: [1.3, 0.0, 0.0, 0.0, 0.0, 4.5] +# If your robot cannot instantaneously reach its acceleration limit, the permitted change can be controlled with these +# gains +acceleration_gains: [0.8, 0.0, 0.0, 0.0, 0.0, 0.9] +# If your robot cannot instantaneously reach its deceleration limit, the permitted change can be controlled with these +# gains +deceleration_gains: [1.0, 0.0, 0.0, 0.0, 0.0, 1.0] + +# [ADVANCED] The process noise covariance matrix can be difficult to tune, and can vary for each application, so it is +# exposed as a configuration parameter. This matrix represents the noise we add to the total error after each +# prediction step. The better the omnidirectional motion model matches your system, the smaller these values can be. +# However, if users find that a given variable is slow to converge, one approach is to increase the +# process_noise_covariance diagonal value for the variable in question, which will cause the filter's predicted error +# to be larger, which will cause the filter to trust the incoming measurement more during correction. The values are +# ordered as x, y, z, roll, pitch, yaw, vx, vy, vz, vroll, vpitch, vyaw, ax, ay, az. Defaults to the matrix below if +# unspecified. +process_noise_covariance: [0.05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0.05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0.06, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0.03, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0.03, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0.06, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0.025, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0.025, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0.04, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.01, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.01, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.02, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.01, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.01, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.015] + +# [ADVANCED] This represents the initial value for the state estimate error covariance matrix. Setting a diagonal +# value (variance) to a large value will result in rapid convergence for initial measurements of the variable in +# question. Users should take care not to use large values for variables that will not be measured directly. The values +# are ordered as x, y, z, roll, pitch, yaw, vx, vy, vz, vroll, vpitch, vyaw, ax, ay, az. Defaults to the matrix below +#if unspecified. +initial_estimate_covariance: [1e-9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1e-9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1e-9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1e-9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1e-9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1e-9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1e-9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1e-9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1e-9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1e-9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1e-9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1e-9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1e-9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1e-9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1e-9] + diff --git a/src/htc_vive_tracker_alg_node.cpp b/src/htc_vive_tracker_alg_node.cpp index 4ebf16d..98ca1b8 100644 --- a/src/htc_vive_tracker_alg_node.cpp +++ b/src/htc_vive_tracker_alg_node.cpp @@ -229,6 +229,7 @@ bool HtcViveTrackerAlgNode::get_button_serverCallback(iri_htc_vive_tracker::GetB if (!res.success) res.message = this->alg_.DEVICE_NOT_FOUND_MSG; return true; } + nav_msgs::Odometry HtcViveTrackerAlgNode::CreateOdometryFromPoseVel(const geometry_msgs::PoseStamped & pose, const Velocity & vel){ geometry_msgs::TwistWithCovariance twist_msg; @@ -238,10 +239,22 @@ nav_msgs::Odometry HtcViveTrackerAlgNode::CreateOdometryFromPoseVel(const geomet twist_msg.twist.angular.x = vel.angular_velocity.x; twist_msg.twist.angular.y = vel.angular_velocity.y; twist_msg.twist.angular.z = vel.angular_velocity.z; - //TODO Fill covariance + + twist_msg.covariance = {0.01, 0, 0, 0, 0, 0, // covariance on pose x + 0, 0.01, 0, 0, 0, 0, // covariance on pose y + 0, 0, 0.01, 0, 0, 0, // covariance on pose z + 0, 0, 0, 1, 0, 0, // covariance on rot x + 0, 0, 0, 0, 1, 0, // covariance on rot y + 0, 0, 0, 0, 0, 1}; // covariance on rot z + geometry_msgs::PoseWithCovariance pose_msg; pose_msg.pose = pose.pose; - //TODO Fill covariance + pose_msg.covariance = {0.01, 0, 0, 0, 0, 0, // covariance on pose x + 0, 0.01, 0, 0, 0, 0, // covariance on pose y + 0, 0, 0.01, 0, 0, 0, // covariance on pose z + 0, 0, 0, 1, 0, 0, // covariance on rot x + 0, 0, 0, 0, 1, 0, // covariance on rot y + 0, 0, 0, 0, 0, 1}; // covariance on rot z nav_msgs::Odometry odom; odom.header.stamp = ros::Time::now(); @@ -251,6 +264,7 @@ nav_msgs::Odometry HtcViveTrackerAlgNode::CreateOdometryFromPoseVel(const geomet odom.twist = twist_msg; return odom; } + /* main function */ int main(int argc,char *argv[]) { -- GitLab