From d35c17f93faa8609c2b1e2ef4f2b307c8d9dfce6 Mon Sep 17 00:00:00 2001
From: Angel <roangel@student.ethz.ch>
Date: Tue, 19 Sep 2017 21:15:25 +0200
Subject: [PATCH] need to try with CFs

---
 pps_ws/src/d_fall_pps/CMakeLists.txt          |   4 +
 .../GUI_Qt/studentGUI/studentGUI.pro.user     |   2 +-
 pps_ws/src/d_fall_pps/param/ClientConfig.yaml |   2 +-
 pps_ws/src/d_fall_pps/param/Crazyflie.db      |   4 +-
 .../src/d_fall_pps/src/FollowN_1Service.cpp   | 251 ++++++++++++++++++
 5 files changed, 258 insertions(+), 5 deletions(-)
 create mode 100644 pps_ws/src/d_fall_pps/src/FollowN_1Service.cpp

diff --git a/pps_ws/src/d_fall_pps/CMakeLists.txt b/pps_ws/src/d_fall_pps/CMakeLists.txt
index da5513ed..58a69ae5 100755
--- a/pps_ws/src/d_fall_pps/CMakeLists.txt
+++ b/pps_ws/src/d_fall_pps/CMakeLists.txt
@@ -240,6 +240,7 @@ add_executable(CustomControllerService src/CustomControllerService.cpp)
 add_executable(CentralManagerService src/CentralManagerService.cpp src/CrazyflieIO.cpp)
 add_executable(CircleControllerService src/CircleControllerService.cpp)
 add_executable(FollowCrazyflieService src/FollowCrazyflieService.cpp)
+add_executable(FollowN_1Service src/FollowN_1Service.cpp)
 
 
 
@@ -286,6 +287,7 @@ add_dependencies(CustomControllerService d_fall_pps_generate_messages_cpp ${catk
 add_dependencies(CentralManagerService d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
 add_dependencies(CircleControllerService d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
 add_dependencies(FollowCrazyflieService d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
+add_dependencies(FollowN_1Service d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
 
 # GUI-- dependencies
 add_dependencies(my_GUI d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
@@ -325,6 +327,8 @@ target_link_libraries(CircleControllerService ${catkin_LIBRARIES})
 
 target_link_libraries(FollowCrazyflieService ${catkin_LIBRARIES})
 
+target_link_libraries(FollowN_1Service ${catkin_LIBRARIES})
+
 # GUI -- link libraries
 target_link_libraries(my_GUI Qt5::Widgets) # GUI -- let my_GUI have acesss to Qt stuff
 target_link_libraries(my_GUI Qt5::Svg)
diff --git a/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/studentGUI.pro.user b/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/studentGUI.pro.user
index 8c884a79..d14c1b24 100644
--- a/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/studentGUI.pro.user
+++ b/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/studentGUI.pro.user
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE QtCreatorProject>
-<!-- Written by QtCreator 3.5.1, 2017-09-08T16:35:09. -->
+<!-- Written by QtCreator 3.5.1, 2017-09-08T19:15:31. -->
 <qtcreator>
  <data>
   <variable>EnvironmentId</variable>
diff --git a/pps_ws/src/d_fall_pps/param/ClientConfig.yaml b/pps_ws/src/d_fall_pps/param/ClientConfig.yaml
index 4e69d2ac..c5c9a5d4 100755
--- a/pps_ws/src/d_fall_pps/param/ClientConfig.yaml
+++ b/pps_ws/src/d_fall_pps/param/ClientConfig.yaml
@@ -1,5 +1,5 @@
 safeController: "SafeControllerService/RateController"
-customController: "CustomControllerService/CustomController"
+customController: "FollowN_1ControllerService/FollowController"
 strictSafety: true
 angleMargin: 0.6
 
diff --git a/pps_ws/src/d_fall_pps/param/Crazyflie.db b/pps_ws/src/d_fall_pps/param/Crazyflie.db
index 54a5f7cb..01656942 100644
--- a/pps_ws/src/d_fall_pps/param/Crazyflie.db
+++ b/pps_ws/src/d_fall_pps/param/Crazyflie.db
@@ -1,3 +1 @@
-5,PPS_CF02,0/8/2M,1,-0.401205,0.729533,-0.2,0.289141,1.25551,2
-6,PPS_CF08,0/56/2M,2,-0.997887,-0.285942,-0.2,0.00653145,0.214912,2
-4,PPS_CF05,0/32/2M,0,-1.02122,0.593954,-0.2,-0.298455,1.15782,2
+8,cfOne,0/76/2M/E7E7E7E701,0,-1.6,-1.12,-0.2,0.52,0.96,2
diff --git a/pps_ws/src/d_fall_pps/src/FollowN_1Service.cpp b/pps_ws/src/d_fall_pps/src/FollowN_1Service.cpp
new file mode 100644
index 00000000..b5ab8390
--- /dev/null
+++ b/pps_ws/src/d_fall_pps/src/FollowN_1Service.cpp
@@ -0,0 +1,251 @@
+//    Alternate controller that is expected to work.
+//    Copyright (C) 2017  Cyrill Burgener, Marco Mueller, Philipp Friedli
+//
+//    This program is free software: you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation, either version 3 of the License, or
+//    (at your option) any later version.
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License
+//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+#include <math.h>
+#include <stdlib.h>
+#include "ros/ros.h"
+#include <std_msgs/String.h>
+#include <ros/package.h>
+#include "std_msgs/Float32.h"
+
+#include "d_fall_pps/CrazyflieData.h"
+#include "d_fall_pps/Setpoint.h"
+#include "d_fall_pps/ControlCommand.h"
+#include "d_fall_pps/Controller.h"
+
+#define PI 3.1415926535
+#define RATE_CONTROLLER 0
+
+using namespace d_fall_pps;
+
+std::vector<float>  ffThrust(4);
+std::vector<float>  feedforwardMotor(4);
+std::vector<float>  motorPoly(3);
+
+std::vector<float>  gainMatrixRoll(9);
+std::vector<float>  gainMatrixPitch(9);
+std::vector<float>  gainMatrixYaw(9);
+std::vector<float>  gainMatrixThrust(9);
+
+//K_infinite of feedback
+std::vector<float> filterGain(6);
+//only for velocity calculation
+std::vector<float> estimatorMatrix(2);
+float prevEstimate[9];
+
+std::vector<float>  setpoint(4);
+float saturationThrust;
+ros::Publisher followPublisher;
+
+CrazyflieData previousLocation;
+
+void loadParameterFloatVector(ros::NodeHandle& nodeHandle, std::string name, std::vector<float>& val, int length) {
+    if(!nodeHandle.getParam(name, val)){
+        ROS_ERROR_STREAM("missing parameter '" << name << "'");
+    }
+    if(val.size() != length) {
+        ROS_ERROR_STREAM("parameter '" << name << "' has wrong array length, " << length << " needed");
+    }
+}
+
+void loadParameters(ros::NodeHandle& nodeHandle) {
+    loadParameterFloatVector(nodeHandle, "feedforwardMotor", feedforwardMotor, 4);
+    loadParameterFloatVector(nodeHandle, "motorPoly", motorPoly, 3);
+
+    for(int i = 0; i < 4; ++i) {
+        ffThrust[i] = motorPoly[2] * feedforwardMotor[i] * feedforwardMotor[i] + motorPoly[1] * feedforwardMotor[i] + motorPoly[0];
+    }
+    saturationThrust = motorPoly[2] * 12000 * 12000 + motorPoly[1] * 12000 + motorPoly[0];
+
+    loadParameterFloatVector(nodeHandle, "gainMatrixRoll", gainMatrixRoll, 9);
+    loadParameterFloatVector(nodeHandle, "gainMatrixPitch", gainMatrixPitch, 9);
+    loadParameterFloatVector(nodeHandle, "gainMatrixYaw", gainMatrixYaw, 9);
+    loadParameterFloatVector(nodeHandle, "gainMatrixThrust", gainMatrixThrust, 9);
+
+    loadParameterFloatVector(nodeHandle, "filterGain", filterGain, 6);
+    loadParameterFloatVector(nodeHandle, "estimatorMatrix", estimatorMatrix, 2);
+
+    loadParameterFloatVector(nodeHandle, "defaultSetpoint", setpoint, 4);
+}
+
+float computeMotorPolyBackward(float thrust) {
+    return (-motorPoly[1] + sqrt(motorPoly[1] * motorPoly[1] - 4 * motorPoly[2] * (motorPoly[0] - thrust))) / (2 * motorPoly[2]);
+}
+
+
+//Kalman
+void estimateState(Controller::Request &request, float (&est)[9]) {
+    // attitude
+    est[6] = request.ownCrazyflie.roll;
+    est[7] = request.ownCrazyflie.pitch;
+    est[8] = request.ownCrazyflie.yaw;
+
+    //velocity & filtering
+    float ahat_x[6]; //estimator matrix times state (x, y, z, vx, vy, vz)
+    ahat_x[0] = 0; ahat_x[1]=0; ahat_x[2]=0;
+    ahat_x[3] = estimatorMatrix[0] * prevEstimate[0] + estimatorMatrix[1] * prevEstimate[3];
+    ahat_x[4] = estimatorMatrix[0] * prevEstimate[1] + estimatorMatrix[1] * prevEstimate[4];
+    ahat_x[5] = estimatorMatrix[0] * prevEstimate[2] + estimatorMatrix[1] * prevEstimate[5];
+
+    
+    float k_x[6]; //filterGain times state
+    k_x[0] = request.ownCrazyflie.x * filterGain[0];
+    k_x[1] = request.ownCrazyflie.y * filterGain[1];
+    k_x[2] = request.ownCrazyflie.z * filterGain[2];
+    k_x[3] = request.ownCrazyflie.x * filterGain[3];
+    k_x[4] = request.ownCrazyflie.y * filterGain[4];
+    k_x[5] = request.ownCrazyflie.z * filterGain[5];
+   
+    est[0] = ahat_x[0] + k_x[0];
+    est[1] = ahat_x[1] + k_x[1];
+	est[2] = ahat_x[2] + k_x[2];
+    est[3] = ahat_x[3] + k_x[3];
+    est[4] = ahat_x[4] + k_x[4];
+    est[5] = ahat_x[5] + k_x[5];
+
+    memcpy(prevEstimate, est, 9 * sizeof(float));
+    
+}
+
+
+void convertIntoBodyFrame(float est[9], float (&state)[9], float yaw_measured) {
+	float sinYaw = sin(yaw_measured);
+    float cosYaw = cos(yaw_measured);
+
+    state[0] = est[0] * cosYaw + est[1] * sinYaw;
+    state[1] = -est[0] * sinYaw + est[1] * cosYaw;
+    state[2] = est[2];
+
+    state[3] = est[3] * cosYaw + est[4] * sinYaw;
+    state[4] = -est[3] * sinYaw + est[4] * cosYaw;
+    state[5] = est[5];
+
+    state[6] = est[6];
+    state[7] = est[7];
+    state[8] = est[8];
+}
+
+bool calculateControlOutput(Controller::Request &request, Controller::Response &response) {
+    CrazyflieData vicon = request.ownCrazyflie;
+	
+	float yaw_measured = request.ownCrazyflie.yaw;
+
+    //publish setpoint for FollowController of another student group
+    Setpoint pubSetpoint;
+    pubSetpoint.x = request.ownCrazyflie.x;
+    pubSetpoint.y = request.ownCrazyflie.y;
+    pubSetpoint.z = request.ownCrazyflie.z;
+    pubSetpoint.yaw = request.ownCrazyflie.yaw;
+    followPublisher.publish(pubSetpoint);
+
+    //move coordinate system to make setpoint origin
+    request.ownCrazyflie.x -= setpoint[0];
+    request.ownCrazyflie.y -= setpoint[1];
+    request.ownCrazyflie.z -= setpoint[2];
+    float yaw = request.ownCrazyflie.yaw - setpoint[3];
+
+    while(yaw > PI) {yaw -= 2 * PI;}
+    while(yaw < -PI) {yaw += 2 * PI;}
+    request.ownCrazyflie.yaw = yaw;
+
+    float est[9]; //px, py, pz, vx, vy, vz, roll, pitch, yaw
+    estimateState(request, est);
+	
+    float state[9]; //px, py, pz, vx, vy, vz, roll, pitch, yaw
+    convertIntoBodyFrame(est, state, yaw_measured);
+
+    //calculate feedback
+    float outRoll = 0;
+    float outPitch = 0;
+    float outYaw = 0;
+    float thrustIntermediate = 0;
+    for(int i = 0; i < 9; ++i) {
+    	outRoll -= gainMatrixRoll[i] * state[i];
+    	outPitch -= gainMatrixPitch[i] * state[i];
+    	outYaw -= gainMatrixYaw[i] * state[i];
+    	thrustIntermediate -= gainMatrixThrust[i] * state[i];
+    }
+
+    //INFORMATION: this ugly fix was needed for the older firmware
+    //outYaw *= 0.5;
+
+    response.controlOutput.roll = outRoll;
+    response.controlOutput.pitch = outPitch;
+    response.controlOutput.yaw = outYaw;
+
+    if(thrustIntermediate > saturationThrust)
+        thrustIntermediate = saturationThrust;
+    else if(thrustIntermediate < -saturationThrust)
+        thrustIntermediate = -saturationThrust;
+
+    response.controlOutput.motorCmd1 = computeMotorPolyBackward(thrustIntermediate + ffThrust[0]);
+    response.controlOutput.motorCmd2 = computeMotorPolyBackward(thrustIntermediate + ffThrust[1]);
+    response.controlOutput.motorCmd3 = computeMotorPolyBackward(thrustIntermediate + ffThrust[2]);
+    response.controlOutput.motorCmd4 = computeMotorPolyBackward(thrustIntermediate + ffThrust[3]);
+
+    response.controlOutput.onboardControllerType = RATE_CONTROLLER;
+
+    previousLocation = request.ownCrazyflie;
+   
+	return true;
+}
+
+//the setpoint is copied from the other crazyflie. This crazyflie should then make the same figure in its own area
+void followCallback(const Setpoint& newSetpoint) {
+    setpoint[0] = newSetpoint.x;
+    setpoint[1] = newSetpoint.y;
+    setpoint[2] = newSetpoint.z;
+    setpoint[3] = newSetpoint.yaw;
+}
+
+
+int main(int argc, char* argv[]) {
+    ros::init(argc, argv, "FollowN_1ControllerService");
+
+    ros::NodeHandle nodeHandle("~");
+    loadParameters(nodeHandle);
+
+    int student_id;
+    ros::NodeHandle namespace_nodeHandle(ros::this_node::getNamespace());
+    if(!namespace_nodeHandle.getParam("studentID", student_id))
+    {
+		ROS_ERROR("Failed to get studentID");
+	}
+
+    followPublisher = nodeHandle.advertise<Setpoint>("/" + std::to_string(student_id) + "/FollowN_1Service/FollowTopic", 1);
+
+    if(student_id != 1)
+    {
+        // subscribe to n-1 setpoint
+        ros::Subscriber followSubscriber = nodeHandle.subscribe("/" + std::to_string(student_id - 1) + "/FollowN_1Service/FollowTopic", 1, followCallback);
+    }
+    else
+    {
+        // what is the setpoint for 1? 0 0 0.5 0
+        setpoint[0] = 0;
+        setpoint[1] = 0;
+        setpoint[2] = 0.5;
+        setpoint[3] = 0;
+    }
+
+
+    ros::ServiceServer service = nodeHandle.advertiseService("FollowController", calculateControlOutput);
+    ROS_INFO("FollowN_1Service ready");
+
+    ros::spin();
+
+    return 0;
+}
-- 
GitLab