5#ifndef EKF_SENSOR_FUSION_H
6#define EKF_SENSOR_FUSION_H
18#include <unordered_map>
24template <
typename MotionModelType,
typename ObservationModelType>
class EKFSensorFusion
41 void predict(
const std::string &input_message,
const std::string &sensor_message,
48 std::optional<std::string>
50 std::chrono::milliseconds timeout = std::chrono::milliseconds(1000));
64 bool has_matrix(
const std::string &name)
const;
71 std::map<std::string, matrix_type> matrices_;
72 std::unique_ptr<bitrl::network::MqttSubscriber> input_subscriber_;
73 std::unordered_map<topic_type, std::unique_ptr<bitrl::network::MqttSubscriber>> sensors_;
74 std::unordered_map<topic_type, SensorTypeEnum> topic_to_sensor_type_;
77template <
typename MotionModelType,
typename ObservationModelType>
80 : motion_model_(&motion_model), observation_model_(&observation_model), sensors_(),
81 topic_to_sensor_type_()
85template <
typename MotionModelType,
typename ObservationModelType>
90template <
typename MotionModelType,
typename ObservationModelType>
92 const std::string &name)
const
94 auto itr = matrices_.find(name);
95 return itr != matrices_.end();
98template <
typename MotionModelType,
typename ObservationModelType>
103 auto itr = matrices_.find(name);
104 if (itr == matrices_.end())
106 throw std::invalid_argument(
"Matrix: " + name +
" does not exist");
111template <
typename MotionModelType,
typename ObservationModelType>
116 auto itr = matrices_.find(name);
117 if (itr == matrices_.end())
119 throw std::invalid_argument(
"Matrix: " + name +
" does not exist");
124template <
typename MotionModelType,
typename ObservationModelType>
129 if (name !=
"Q" && name !=
"K" && name !=
"R" && name !=
"P")
131 throw std::logic_error(
"Invalid matrix name. Name: " + name +
" not in [Q, K, R, P]");
133 matrices_.insert_or_assign(name, mat);
137template <
typename MotionModelType,
typename ObservationModelType>
139 const std::string &mqtt_url,
const topic_type &topic)
141 input_subscriber_ = std::make_unique<bitrl::network::MqttSubscriber>(mqtt_url, topic);
142 input_subscriber_->connect();
145template <
typename MotionModelType,
typename ObservationModelType>
147 const std::string &mqtt_url,
const std::string &topic,
SensorTypeEnum sensor_type)
149 auto subscriber = std::make_unique<bitrl::network::MqttSubscriber>(mqtt_url, topic);
150 subscriber->connect();
151 sensors_[topic] = std::move(subscriber);
152 topic_to_sensor_type_.insert({topic, sensor_type});
155template <
typename MotionModelType,
typename ObservationModelType>
157 const std::string &topic, std::chrono::milliseconds timeout)
160 auto topic_itr = sensors_.find(topic);
161 if (topic_itr == sensors_.end())
166 auto topic_message = topic_itr->second->poll(timeout);
168 if (!topic_message.has_value())
173 return topic_message;
176template <
typename MotionModelType,
typename ObservationModelType>
181 for (
auto &sensor : sensors_)
183 auto sensor_message = read_from_topic(sensor.first, std::chrono::milliseconds(200));
187 if (sensor_message.has_value())
190 auto input_message = input_subscriber_->poll(std::chrono::milliseconds(1000));
192 if (input_message.has_value())
194 predict(input_message.value(), sensor_message.value(), sensor.first);
195 update(sensor_message.value(), sensor.first);
199 std::cout <<
"No input message received: " << std::endl;
205template <
typename MotionModelType,
typename ObservationModelType>
207 const std::string &input_message,
const std::string &sensor_message,
const topic_type &topic)
211 motion_model_->evaluate(input_message, sensor_message, topic);
213 std::cout <<
"Model evaluation finished...: " << std::endl;
215 auto &P = (*this)[
"P"];
216 auto &Q = (*this)[
"Q"];
220 auto &F = motion_model_->get_matrix(
"F");
221 auto F_T = F.transpose();
225 if (motion_model_->has_matrix(
"L"))
227 auto &L = motion_model_->get_matrix(
"L");
228 auto L_T = L.transpose();
238template <
typename MotionModelType,
typename ObservationModelType>
240 const std::string &sensor_message,
const topic_type &topic)
242 std::cout <<
"Update sensor message: " << sensor_message << std::endl;
243 auto &state = motion_model_->get_state();
244 auto &P = (*this)[
"P"];
245 auto &R = (*this)[
"R"];
247 auto z = observation_model_->convert_sensor_message(sensor_message, topic);
248 auto zpred = observation_model_->evaluate(state.as_vector());
252 auto &H = observation_model_->get_matrix(
"H");
253 auto H_T = H.transpose();
261 if (observation_model_->has_matrix(
"M"))
263 auto &M = observation_model_->get_matrix(
"M");
264 auto M_T = M.transpose();
272 auto S_inv = S.inverse();
276 auto &K = (*this)[
"K"];
281 auto K = P * H_T * S_inv;
285 auto &K = (*this)[
"K"];
286 auto innovation = z - zpred;
289 auto innovation_t = innovation.transpose();
291 if (K.cols() != innovation_t.rows())
293 throw std::runtime_error(
294 "Matrix columns: " + std::to_string(K.cols()) +
295 " not equal to vector size: " + std::to_string(innovation_t.rows()));
299 state += K * innovation_t;
302 auto I = matrix_type::Identity(state.size(), state.size());
Definition ekf_sensor_fusion.h:25
void step()
Definition ekf_sensor_fusion.h:177
std::optional< std::string > read_from_topic(const topic_type &topic, std::chrono::milliseconds timeout=std::chrono::milliseconds(1000))
Definition ekf_sensor_fusion.h:156
~EKFSensorFusion()
Definition ekf_sensor_fusion.h:86
EKFSensorFusion & with_matrix(const std::string &name, const matrix_type &mat)
Definition ekf_sensor_fusion.h:126
EKFSensorFusion(motion_model_type &motion_model, observation_model_type &observation_model)
Definition ekf_sensor_fusion.h:78
void update(const std::string &sensor_message, const topic_type &topic)
Definition ekf_sensor_fusion.h:239
void add_sensor_topic(const std::string &mqtt_url, const topic_type &topic, SensorTypeEnum sensor_type)
Definition ekf_sensor_fusion.h:146
MotionModelType motion_model_type
Definition ekf_sensor_fusion.h:27
const matrix_type & operator[](const std::string &name) const
Returns the name-th matrix.
Definition ekf_sensor_fusion.h:100
DynMat< real_t > matrix_type
Definition ekf_sensor_fusion.h:29
ObservationModelType observation_model_type
Definition ekf_sensor_fusion.h:28
bool has_matrix(const std::string &name) const
Returns true if the matrix with the given name exists.
Definition ekf_sensor_fusion.h:91
void predict(const std::string &input_message, const std::string &sensor_message, const topic_type &topic)
Definition ekf_sensor_fusion.h:206
std::string topic_type
Definition ekf_sensor_fusion.h:30
void add_input_topic(const std::string &mqtt_url, const topic_type &topic)
Definition ekf_sensor_fusion.h:138
SensorTypeEnum
Definition sensor_type_enum.h:14
Definition bitrl_consts.h:14
Eigen::MatrixX< T > DynMat
Dynamically sized matrix to use around the library.
Definition bitrl_types.h:49