diff --git a/clever/CMakeLists.txt b/clever/CMakeLists.txt
index 5af4fa36..6ce7ec76 100644
--- a/clever/CMakeLists.txt
+++ b/clever/CMakeLists.txt
@@ -165,10 +165,14 @@ add_executable(rc src/rc.cpp)
add_executable(camera_markers src/camera_markers.cpp)
+add_executable(frames src/frames.cpp)
+
target_link_libraries(rc ${catkin_LIBRARIES})
target_link_libraries(camera_markers ${catkin_LIBRARIES})
+target_link_libraries(frames ${catkin_LIBRARIES})
+
## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the
## target back to the shorter version for ease of user use
diff --git a/clever/launch/clever.launch b/clever/launch/clever.launch
index 95f4e2a7..998ef361 100644
--- a/clever/launch/clever.launch
+++ b/clever/launch/clever.launch
@@ -43,11 +43,12 @@
-
-
+
+
+
diff --git a/clever/src/frames.cpp b/clever/src/frames.cpp
new file mode 100644
index 00000000..f0d5a8b0
--- /dev/null
+++ b/clever/src/frames.cpp
@@ -0,0 +1,63 @@
+/*
+ * Auxiliary TF frames for CLEVER drone kit:
+ * - Body frame (drone body with zero pitch and roll).
+ * - TODO: REP-0105 `odom` frame emulation: continuous frame without discrete jumps.
+ * - TODO: Terrain frame (base on ALTITUDE message).
+ * - TODO: map_upside_down frame
+ * - TODO: home frame?
+ *
+ * Copyright (C) 2018 Copter Express Technologies
+ *
+ * Author: Oleg Kalachev
+ *
+ * Distributed under MIT License (available at https://opensource.org/licenses/MIT).
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ */
+
+// TODO: consider implementing as a mavros plugin
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using std::string;
+
+static std::shared_ptr br;
+static geometry_msgs::TransformStamped body;
+
+inline void publishBody(const geometry_msgs::PoseStamped& pose)
+{
+ // Get only yaw from pose
+ tf::Quaternion q;
+ q.setRPY(0, 0, tf::getYaw(pose.pose.orientation));
+ tf::quaternionTFToMsg(q, body.transform.rotation);
+
+ body.transform.translation.x = pose.pose.position.x;
+ body.transform.translation.y = pose.pose.position.y;
+ body.transform.translation.z = pose.pose.position.z;
+ body.header.frame_id = pose.header.frame_id;
+ body.header.stamp = pose.header.stamp;
+ br->sendTransform(body);
+}
+
+void poseCallback(const geometry_msgs::PoseStamped& pose)
+{
+ publishBody(pose);
+}
+
+int main(int argc, char **argv) {
+ ros::init(argc, argv, "frames");
+ ros::NodeHandle nh, nh_priv("~");
+
+ nh_priv.param("body/frame_id", body.child_frame_id, "body");
+
+ br = std::make_shared();
+ ros::Subscriber pose_sub = nh.subscribe("mavros/local_position/pose", 1, &poseCallback);
+ ROS_INFO("frames: ready");
+ ros::spin();
+}