diff --git a/.gitignore b/.gitignore
index 40f8a97..065dea8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,10 +2,13 @@ config/mocap_*
launch/cortex_bridge.launch
launch/debug.launch
launch/klausen_dampen.launch
+launch/mocap_*
src/development_*
src/killswitch_client.py
src/land_client.py
+src/MoCap_*.py
src/Mocap_*.py
+src/mocap_*
src/segmented_tether.py
src/segmented_tether_fast.py
msg/Marker.msg
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e1717b5..1d72db3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -95,11 +95,11 @@ add_dependencies(pathFollow_node ${${PROJECT_NAME}EXPORTEDTARGETS} ${catkin_EXPO
#add_dependencies(mocap_offb_node ${${PROJECT_NAME}EXPORTEDTARGETS} ${catkin_EXPORTED_TARGETS})
-add_executable(mocap_pathFollow_node src/mocap_path_follow.cpp)
+#add_executable(mocap_pathFollow_node src/mocap_path_follow.cpp)
-target_link_libraries(mocap_pathFollow_node ${catkin_LIBRARIES})
+#target_link_libraries(mocap_pathFollow_node ${catkin_LIBRARIES})
-add_dependencies(mocap_pathFollow_node ${${PROJECT_NAME}EXPORTEDTARGETS} ${catkin_EXPORTED_TARGETS})
+#add_dependencies(mocap_pathFollow_node ${${PROJECT_NAME}EXPORTEDTARGETS} ${catkin_EXPORTED_TARGETS})
## Declare a C++ library
# add_library(${PROJECT_NAME}
diff --git a/airframes/18.04/4000_spiri b/airframes/18.04/4000_spiri
new file mode 100644
index 0000000..81ad67a
--- /dev/null
+++ b/airframes/18.04/4000_spiri
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# @name Generic Quadcopter
+#
+# @type Quadrotor x
+# @class Copter
+
+. ${R}etc/init.d/rc.mc_defaults
+
+param set-default MC_ROLLRATE_K 2.35
+param set-default MC_ROLLRATE_D 0.0032
+param set-default MC_ROLLRATE_I 0.15
+
+param set-default MC_PITCHRATE_K 2.35
+param set-default MC_PITCHRATE_D 0.0032
+param set-default MC_PITCHRATE_I 0.15
+
+param set-default MPC_Z_VEL_MAX_UP 1.0
+
+param set EKF2_AID_MASK 1
+param set EKF2_HGT_MODE 0
+param set SYS_FAILURE_EN 0
+
+set MIXER quad_x
+set PWM_OUT 1234
diff --git a/airframes/18.04/4001_spiri_with_tether b/airframes/18.04/4001_spiri_with_tether
new file mode 100644
index 0000000..0bb23c7
--- /dev/null
+++ b/airframes/18.04/4001_spiri_with_tether
@@ -0,0 +1,26 @@
+#!/bin/sh
+#
+# @name Generic Quadcopter
+#
+# @type Quadrotor x
+# @class Copter
+
+. ${R}etc/init.d/rc.mc_defaults
+
+param set MC_ROLLRATE_K 2.35
+param set MC_ROLLRATE_D 0.0030
+param set MC_ROLLRATE_I 0.15
+
+param set MC_PITCHRATE_K 2.35
+param set MC_PITCHRATE_D 0.0030
+param set MC_PITCHRATE_I 0.15
+
+param set MPC_Z_VEL_MAX_UP 0.5
+param set MPC_TKO_SPEED 1.0
+
+param set EKF2_AID_MASK 1
+param set EKF2_HGT_MODE 0
+param set SYS_FAILURE_EN 0
+
+set MIXER quad_x
+set PWM_OUT 1234
diff --git a/airframes/4000_spiri b/airframes/20.04/4000_spiri
similarity index 100%
rename from airframes/4000_spiri
rename to airframes/20.04/4000_spiri
diff --git a/airframes/4001_spiri_with_tether b/airframes/20.04/4001_spiri_with_tether
similarity index 85%
rename from airframes/4001_spiri_with_tether
rename to airframes/20.04/4001_spiri_with_tether
index f419a52..07334d2 100644
--- a/airframes/4001_spiri_with_tether
+++ b/airframes/20.04/4001_spiri_with_tether
@@ -16,11 +16,6 @@ param set-default MC_PITCHRATE_D 0.0060
param set-default MC_PITCHRATE_I 0.35
param set-default MPC_Z_P 0.70
-
-#param load spiri_param/Vehicle_230_Parameters.params
-
-#param set-default MC_PITCHRATE_P 0.0889
-#param set-default MC_ROLLRATE_P 0.0957
param set-default CA_AIRFRAME 0
param set-default CA_ROTOR_COUNT 4
@@ -45,8 +40,7 @@ param set-default COM_RCL_EXCEPT 4
param set-default MPC_Z_VEL_MAX_UP 1.0
-param set-default COM_RCL_EXCEPT 4
-param set-default NAV_RCL_ACT 1
+param set-default COM_RCL_EXCEPT 4 # Ignores no RC failsafe (not needed for simulations)
set MIXER quad_x
set PWM_OUT 1234
diff --git a/config/Ctrl_param.yaml b/config/Ctrl_param.yaml
deleted file mode 100644
index e50ad51..0000000
--- a/config/Ctrl_param.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-# Ros param when using Klausen Ctrl
-wait_time: 30
-#drone_mass: 0.614 # weight with new battery
-drone_mass: 0.602 # weight with old battery
-#drone_mass: 1.437 # spiri weight
-
-#pload_mass: 0.15 # Pload mass with 100g weight
-pload_mass: 0.10 # Pload mass with 50g weight
-#pload_mass: 0.05 # Pload mass with just basket
-#pload_mass: 0.25
-
-use_ctrl: false
-
-
diff --git a/config/gazebo_config.yaml b/config/gazebo_config.yaml
deleted file mode 100644
index 4148cfa..0000000
--- a/config/gazebo_config.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-# Ros param when not using Klausen Ctrl
-waypoints: {x: 0.0, y: -0.25, z: 1.5}
-square_x: [0.5,1,1,1,0.5,0,0]
-square_y: [0,0,0.5,1,1,1,0.5]
-hover_throttle: 0.46 # with 500g
-hover_throttle: 0.51 # with 250g???
diff --git a/config/mocapGazebo_params.yaml b/config/mocapGazebo_params.yaml
new file mode 100644
index 0000000..79c4ac5
--- /dev/null
+++ b/config/mocapGazebo_params.yaml
@@ -0,0 +1,14 @@
+# Ros param when using Klausen Ctrl
+wait_time: 30 # parameter which can be set to run desired tests at a desired time
+#drone_mass: 0.614 # weight with new battery
+drone_mass: 0.602
+pload_mass: 0.1 # mass of payload. Needs to be changed in spiri_with_tether file as well
+#pload_mass: 0.15 # Pload mass with 100g weight
+pload_mass: 0.10 # Pload mass with 50g weight
+#pload_mass: 0.05 # Pload mass with just basket
+#pload_mass: 0.25
+use_ctrl: false # starts PX4 without attitude controller
+waypoints: {x: 0.0, y: 0.0, z: 5.0} # takeoff waypoints
+# sets waypoints to run a square test
+square_x: [0.5,1,1,1,0.5,0,0]
+square_y: [0,0,0.5,1,1,1,0.5]
diff --git a/config/mocapLab_params.yaml b/config/mocapLab_params.yaml
new file mode 100644
index 0000000..eae0f55
--- /dev/null
+++ b/config/mocapLab_params.yaml
@@ -0,0 +1,27 @@
+# Ros param when using Klausen Ctrl
+wait_time: 30 # parameter which can be set to run desired tests at a desired time
+
+# DRONE MASSES
+#drone_mass: 0.614 # weight with new battery
+drone_mass: 0.602
+
+#PLOAD MASSES
+#pload_mass: 0.15 # Pload mass with 100g weight
+pload_mass: 0.10 # Pload mass with 50g weight
+#pload_mass: 0.05 # Pload mass with just basket
+#pload_mass: 0.25
+
+# CTRL PARAMETER - should be false to start always
+use_ctrl: false # starts PX4 without attitude controller
+
+waypoints: {x: 0.0, y: 0.0, z: 1.75} # takeoff waypoints
+
+# sets waypoints to run a square test
+square_x: [0.5,1,1,1,0.5,0,0]
+square_y: [0,0,0.5,1,1,1,0.5]
+
+# HOVER THROTTLE - Changes depending on mass of pload and drone
+# hover_throttle: 0.32 # Hover throttle with pload 0.15 kg
+hover_throttle: 0.28 # Hover throttle with pload 0.10 kg
+# hover_throttle: 0.22 # Hover throttle with no pload
+#hover_throttle: 0.26 # Hover throttle with pload 0.05 kg
diff --git a/config/noCtrl_param.yaml b/config/noCtrl_param.yaml
deleted file mode 100644
index 4d81a8c..0000000
--- a/config/noCtrl_param.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-# Ros param when not using Klausen Ctrl
-wait_time: 40
-drone_mass: 0.5841
-#drone_mass: 1.437
-pload_mass: 0.10
-
-
diff --git a/config/spiri_params.yaml b/config/spiri_params.yaml
new file mode 100644
index 0000000..7255a5c
--- /dev/null
+++ b/config/spiri_params.yaml
@@ -0,0 +1,9 @@
+# Set useful ROS parameters for simulation
+wait_time: 30 # parameter which can be set to run desired tests at a desired time
+drone_mass: 1.437 # mass of drone
+pload_mass: 0.25 # mass of payload
+use_ctrl: false # starts PX4 without attitude controller - needs to be set to false to takeoff
+waypoints: {x: 0.0, y: 0.0, z: 5.0} # takeoff waypoints
+# sets waypoints to run a square test
+square_x: [0.5,1,1,1,0.5,0,0]
+square_y: [0,0,0.5,1,1,1,0.5]
diff --git a/launch/headless_spiri_mocap.launch b/launch/headless_spiri_mocap.launch
new file mode 100644
index 0000000..0ed8922
--- /dev/null
+++ b/launch/headless_spiri_mocap.launch
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/launch/headless_spiri_with_tether_mocap.launch b/launch/headless_spiri_with_tether_mocap.launch
new file mode 100644
index 0000000..1c0bb7e
--- /dev/null
+++ b/launch/headless_spiri_with_tether_mocap.launch
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/launch/mocap_oscillation_damp.launch b/launch/mocap_oscillation_damp.launch
index 4a86ca8..a03d9d3 100644
--- a/launch/mocap_oscillation_damp.launch
+++ b/launch/mocap_oscillation_damp.launch
@@ -14,13 +14,8 @@ Launch file to use klausen oscillaton damping ctrl in Gazebo
-
-
-
-
-
-
+
diff --git a/launch/mocap_sim.launch b/launch/mocap_sim.launch
index 9a353bb..6cd2bdd 100644
--- a/launch/mocap_sim.launch
+++ b/launch/mocap_sim.launch
@@ -3,12 +3,10 @@
Launch file to use klausen oscillaton damping ctrl in Gazebo
/-->
-
-
- should be mocap but will use gazebo since it is still sim <-->
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
+
+
diff --git a/launch/mocap_takeoff_noCtrl.launch b/launch/mocap_takeoff_noCtrl.launch
deleted file mode 100644
index bc2574a..0000000
--- a/launch/mocap_takeoff_noCtrl.launch
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/launch/oscillation_damp.launch b/launch/oscillation_damp.launch
index 40aaaf2..e811eeb 100644
--- a/launch/oscillation_damp.launch
+++ b/launch/oscillation_damp.launch
@@ -5,11 +5,9 @@ Launch file to use klausen oscillaton damping ctrl in Gazebo
-
-
-
+
-
+
@@ -37,7 +35,6 @@ Launch file to use klausen oscillaton damping ctrl in Gazebo
pkg="oscillation_ctrl"
type="klausen_control.py"
name="klausenCtrl_node"
- launch-prefix="xterm -e"
/>
ceiling. Otherwise, it returns
- value back
- """
- # initilize sign
- sign = 1
-
- # check if value is negative
- if value < 0.0:
- sign = -1
- # Cutoff value at ceiling
- if (value > ceiling or value < -ceiling):
- output = sign*ceiling
- else:
- output = value
- return output
def euler_array(self,orientation):
"""
@@ -171,7 +147,6 @@ class Main:
# Determine thetadot
self.loadAngles.thetadot = (self.loadAngles.theta - self.thetabuf)/self.dt
- self.loadAngles.thetadot = self.cutoff(self.loadAngles.thetadot,self.thetadot_max)
self.thetabuf = self.loadAngles.theta
# Determine phi (roll)
@@ -184,7 +159,6 @@ class Main:
# Determine phidot
self.loadAngles.phidot = (self.loadAngles.phi - self.phibuf)/self.dt
- self.loadAngles.phidot = self.cutoff(self.loadAngles.phidot,self.phidot_max)
self.phibuf = self.loadAngles.phi # Update buffer
else: # Otherwise, vars = 0
@@ -204,17 +178,18 @@ class Main:
rospy.loginfo("Get Link State call failed: {0}".format(e))
def user_feedback(self,gui_timer):
- # Print and save results
- #print "\n"
+ print ("\n")
rospy.loginfo("")
- print"Roll: "+str(round(self.drone_Eul[0]*180/3.14,2))
- print"Pitch: " +str(round(self.drone_Eul[1]*180/3.14,2))
- print"Yaw: " +str(round(self.drone_Eul[2]*180/3.14,2))
- print "drone pos.x: " + str(round(self.drone_Px,2))
- print "drone pos.y: " + str(round(self.drone_Py,2))
- print "drone pos.z: " + str(round(self.drone_Pz,2))
- print "phi: " + str(round(self.loadAngles.phi*180/3.14,3))
- print "theta: " + str(round(self.loadAngles.theta*180/3.14,3))
+ print("Drone pos.x: " + str(round(self.drone_Px,2)))
+ print("Drone pos.y: " + str(round(self.drone_Py,2)))
+ print("Drone pos.z: " + str(round(self.drone_Pz,2)))
+ print("Roll: "+str(round(self.drone_Eul[0]*180/3.14,2)))
+ print("Pitch: " +str(round(self.drone_Eul[1]*180/3.14,2)))
+ print("Yaw: " +str(round(self.drone_Eul[2]*180/3.14,2)))
+ if self.pload:
+ print("Tether length: " + str(round(self.tetherL,2)))
+ print("Theta: " + str(round(self.loadAngles.theta*180/3.14,2)))
+ print("Phi: " + str(round(self.loadAngles.phi*180/3.14,2)))
def path_follow(self,path_timer):
now = rospy.get_time()
diff --git a/src/MoCap_Localization_noTether.py b/src/MoCap_Localization_noTether.py
deleted file mode 100755
index 1fcd148..0000000
--- a/src/MoCap_Localization_noTether.py
+++ /dev/null
@@ -1,183 +0,0 @@
-#!/usr/bin/env python2.7
-
-### Cesar Rodriguez Feb 2022
-### Script to determine payload and drone state using mocap
-
-import rospy, tf
-import rosservice
-import time
-import math
-from tf.transformations import *
-from oscillation_ctrl.msg import tethered_status
-from geometry_msgs.msg import PoseStamped, Point
-from std_msgs.msg import Bool
-
-class Main:
-
- def __init__(self):
-
- # rate(s)
- rate = 120 # rate for the publisher method, specified in Hz -- 20 Hz
-
- # Variables needed for testing start
- self.tstart = rospy.get_time() # Keep track of the start time
- while self.tstart == 0.0: # Need to make sure get_rostime works
- self.tstart = rospy.get_time()
-
- ### -*-*-*- Do not need this unless a test is being ran -*-*-*- ###
- # How long should we wait before before starting test
- #self.param_exists = False
- #while self.param_exists == False:
- # if rospy.has_param('sim/wait'):
- # self.wait = rospy.get_param('sim/wait') # wait time
- # self.param_exists = True
- # elif rospy.get_time() - self.tstart >= 3.0:
- # break
-
- # Will be set to true when test should start
- #self.bool = False
- ### -*-*-*- END -*-*-*- ###
-
- # initialize variables
- self.drone_pose = PoseStamped()
- self.buff_pose = PoseStamped()
-
- self.eul = [0.0,0.0,0.0]
-
- # Max dot values to prevent 'blowup'
- self.phidot_max = 3.0
- self.thetadot_max = 3.0
-
- # variables for message gen
-
-
- # service(s)
-
- # need service list to check if models have spawned
-
-
- # wait for service to exist
-
-
- # publisher(s)
- ### Since there is no tether, we can publish directly to mavros
- self.pose_pub = rospy.Publisher('/mavros/vision_pose/pose', PoseStamped, queue_size=1)
-
- self.pub_timer = rospy.Timer(rospy.Duration(1.0/rate), self.publisher)
-
- # subscriber(s)
- rospy.Subscriber('/cortex/body_pose', PoseStamped, self.bodyPose_cb)
-
- def cutoff(self,value,ceiling):
- """
- Takes in value and returns ceiling
- if value > ceiling. Otherwise, it returns
- value back
- """
- # initilize sign
- sign = 1
-
- # check if value is negative
- if value < 0.0:
- sign = -1
- # Cutoff value at ceiling
- if (value > ceiling or value < -ceiling):
- output = sign*ceiling
- else:
- output = value
- return output
-
- def euler_array(self):
- """
- Takes in pose msg object and outputs array of euler angs:
- eul[0] = Roll
- eul[1] = Pitch
- eul[2] = Yaw
- """
- self.eul = euler_from_quaternion([self.drone_pose.pose.orientation.x,
- self.drone_pose.pose.orientation.y,
- self.drone_pose.pose.orientation.z,
- self.drone_pose.pose.orientation.w])
-
- self.q = quaternion_from_euler(self.eul[0],self.eul[1],self.eul[2])
-
- offset_yaw = math.pi/2
- q_offset = quaternion_from_euler(0,0,-offset_yaw)
-
- self.q = quaternion_multiply(self.q,q_offset)
-
- self.eul = euler_from_quaternion([self.q[0],self.q[1],self.q[2],self.q[3]])
- self.drone_pose.pose.orientation.x = self.q[0]
- self.drone_pose.pose.orientation.y = self.q[1]
- self.drone_pose.pose.orientation.z = self.q[2]
- self.drone_pose.pose.orientation.w = self.q[3]
-
- def FRD_Transform(self):
- '''
- Transforms mocap reading to proper coordinate frame
- '''
-
-# self.drone_pose = self.buff_pose
- self.drone_pose.header.frame_id = "/map"
-
-# self.drone_pose.pose.position.x = 0
-# self.drone_pose.pose.position.y = 0
-# self.drone_pose.pose.position.z = 0.5
-
- #Keep the w same and change x, y, and z as above.
-# self.drone_pose.pose.orientation.x = 0
-# self.drone_pose.pose.orientation.y = 0
-# self.drone_pose.pose.orientation.z = 0
-# self.drone_pose.pose.orientation.w = 1
-
- self.euler_array() # get euler angles of orientation for user
-
-# self.drone_pose.pose.position.x = self.buff_pose.pose.position.y
-# self.drone_pose.pose.position.y = self.buff_pose.pose.position.x
-# self.drone_pose.pose.position.z = -self.buff_pose.pose.position.z
-
-# Keep the w same and change x, y, and z as above.
-# self.drone_pose.pose.orientation.x = self.buff_pose.pose.orientation.y
-# self.drone_pose.pose.orientation.y = self.buff_pose.pose.orientation.x
-# self.drone_pose.pose.orientation.z = -self.buff_pose.pose.orientation.z
-# self.drone_pose.pose.orientation.w = self.buff_pose.pose.orientation.w
-
-# def path_follow(self,path_timer):
-# now = rospy.get_time()
-# if now - self.tstart < self.wait:
-# self.bool = False
-# else:
-# self.bool = True
-# self.pub_wd.publish(self.bool)
-
- def bodyPose_cb(self,msg):
- try:
- self.drone_pose = msg
-
- except ValueError:
- pass
-
- def publisher(self,pub_timer):
- self.FRD_Transform()
- self.pose_pub.publish(self.drone_pose)
- print "\n"
- rospy.loginfo("")
- print "drone pos.x: " + str(round(self.drone_pose.pose.position.x,2))
- print "drone pos.y: " + str(round(self.drone_pose.pose.position.y,2))
- print "drone pos.z: " + str(round(self.drone_pose.pose.position.z,2))
- print "Roll: " + str(round(self.eul[0]*180/3.14,2))
- print "Pitch: " + str(round(self.eul[1]*180/3.14,2))
- print "Yaw: " + str(round(self.eul[2]*180/3.14,2))
-
-
-if __name__=="__main__":
-
- # Initiate ROS node
- rospy.init_node('MoCap_node',anonymous=False)
- try:
- Main() # create class object
- rospy.spin() # loop until shutdown signal
-
- except rospy.ROSInterruptException:
- pass
-
diff --git a/src/klausen_control.py b/src/klausen_control.py
index 6831ea8..d8307ec 100755
--- a/src/klausen_control.py
+++ b/src/klausen_control.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python
### Cesar Rodriguez Aug 2021
### Trajectory controller
@@ -96,12 +96,10 @@ class Main:
self.z2 = np.zeros([5,1]) # [vx;vy;vz;thetadot;phidot] - alpha
# Tuning gains
- self.K1 = np.identity(3)#*0.1
- # self.K1 = np.array([[2,-1,0],[-1,2,-1],[0,-1,2]])
- self.tune_array = np.array([1,1,1,0.1,0.1]).reshape(5,1)
- self.K2 = np.identity(5)#*self.tune_array
- self.tune = 0.1 #1 # Tuning parameter
- self.dist = np.array([0,0,0,0.1,0.1]) # Wind disturbance # np.array([0,0,0,0.01,0.01])
+ self.K1 = np.identity(3)
+ self.K2 = np.identity(5)
+ self.tune = 0.1 # Tuning parameter
+ self.dist = np.array([0,0,0,0.1,0.1]) # Wind disturbance
# Gain terms
self.Kp = np.identity(3) + np.dot(self.K2[:3,:3],self.K1) + self.tune*np.identity(3)
self.Kd = self.tot_m*self.K1 + self.tune*self.K2[:3,:3]
@@ -109,10 +107,8 @@ class Main:
# PD Thrust Controller terms
# gains for thrust PD Controller
- #self.Kp = 3.0
- #self.Kd = 3
- self.Kp_thrust = 1.5 #3.0 #1.5
- self.Kd_thrust = 1.0 #3.0 # 1.0
+ self.Kp_thrust = 1.5
+ self.Kd_thrust = 1.0
self.R = np.empty([3,3]) # rotation matrix
self.e3 = np.array([[0],[0],[1]])
# Get scaling thrust factor, kf
@@ -125,7 +121,6 @@ class Main:
# Topic, msg type, and class callback method
rospy.Subscriber('/status/load_angles', LoadAngles, self.loadAngles_cb)
rospy.Subscriber('/reference/path', RefSignal, self.refsig_cb)
- # rospy.Subscriber('/status/twoBody_status', TetheredStatus, self.dronePos_cb)
rospy.Subscriber('/mavros/local_position/pose', PoseStamped, self.dronePos_cb)
rospy.Subscriber('/mavros/local_position/velocity_body', TwistStamped, self.droneVel_cb)
rospy.Subscriber('/mavros/imu/data', Imu, self.droneAcc_cb)
@@ -187,13 +182,20 @@ class Main:
return [drone_m, pl_m]
def get_kf(self):
- if rospy.has_param('mocap/hover_throttle'):
- hover_throttle = rospy.get_param('mocap/hover_throttle')
+ if rospy.has_param('status/hover_throttle'):
+ hover_throttle = rospy.get_param('status/hover_throttle')
else:
hover_throttle = (self.tot_m*9.81 + 9.57)/34.84 # linear scaling depending on dependent on mass
kf = hover_throttle/(self.tot_m*9.81)
return kf
+ # Check if vehicle has tether
+ def tether_check(self):
+ if self.tether == True:
+ rospy.loginfo_once('TETHER LENGTH: %.2f', self.tetherL)
+ else:
+ rospy.loginfo_once('NO TETHER DETECTED')
+
# --------------------------------------------------------------------------------#
# CALLBACK FUNCTIONS
# --------------------------------------------------------------------------------#
@@ -243,13 +245,6 @@ class Main:
except ValueError:
pass
- # Check if vehicle has tether
- def tether_check(self):
- if self.tether == True:
- rospy.loginfo_once('TETHER LENGTH: %.2f', self.tetherL)
- else:
- rospy.loginfo_once('NO TETHER DETECTED')
-
def waypoints_srv_cb(self):
if '/status/waypoint_tracker' in self.service_list:
rospy.wait_for_service('/status/waypoint_tracker')
@@ -358,17 +353,9 @@ class Main:
# determine Rotation Matrix
self.R_e3 = np.array([[self.R.T[2][0]],[self.R.T[2][1]],[self.R.T[2][2]]])
- # test which one is better:
- # thrust_vector = (9.81*self.tot_m*self.e3 + self.Kp_thrust*self.error + self.Kd_thrust*self.error_vel - self.tot_m*self.path_acc)*self.kf
- # thrust = thrust_vector[0]*self.R_e3[0] + thrust_vector[1]*self.R_e3[1] + thrust_vector[2]*self.R_e3[2]
- ### OR:
thrust_vector = (9.81*self.tot_m + self.Kp_thrust*self.error[2] + self.Kd_thrust*self.error_vel[2] - self.tot_m*self.path_acc[2])*self.kf
- # thrust = thrust_vector/(math.cos(self.EulerAng[0]*self.EulerAng[1])) #####
thrust = thrust_vector/(math.cos(self.EulerPose[0])*math.cos(self.EulerPose[1]))
- # if given Fd...?
- # thrust = self.kf*Fd/(math.cos(self.EulerPose[0])*math.cos(self.EulerPose[1]))
-
# Value needs to be between 0 - 1.0
self.att_targ.thrust = max(0.0,min(thrust,1.0))
@@ -458,16 +445,11 @@ class Main:
dr_orientation = [self.dr_pos.orientation.x, self.dr_pos.orientation.y, self.dr_pos.orientation.z, self.dr_pos.orientation.w]
dr_orientation_inv = quaternion_inverse(dr_orientation)
- # fix_force = self.path_acc
- # fix_force = fix_force[:3].reshape(3,1)
- # fix_force[0] = self.path_acc[1]
- # fix_force[1] = self.path_acc[0]
# Desired body-oriented forces
- # shouldnt it be tot_m*path_acc?
Fd = B + G[:3] + self.tot_m*self.dr_acc - np.dot(self.Kd,z1_dot) - np.dot(self.Kp,self.z1) - np.dot(self.Ki,0.5*self.dt*(self.z1 - self.z1_p))
- # Fd = B + G[:3] + self.tot_m*fix_force - np.dot(self.Kd,z1_dot) - np.dot(self.Kp,self.z1) - np.dot(self.Ki,0.5*self.dt*(self.z1 - self.z1_p))
- # Update self.z1_p for "integration"
+
+ # Update self.z1_p for integration
self.z1_p = self.z1
# Covert Fd into drone frame
@@ -479,11 +461,9 @@ class Main:
self.EulerAng[1] = math.atan(Fd_tf[0]/(self.drone_m*9.81)) # Pitch
self.EulerAng[0] = math.atan(-Fd_tf[1]*math.cos(self.EulerAng[1])/(self.drone_m*9.81)) # Roll
- # rospy.loginfo('Fd before transform: %.2f, %.2f, %.2f' % Fd[0],Fd[1],Fd[2])
-
q = quaternion_from_euler(self.EulerAng[0],self.EulerAng[1],self.EulerAng[2])
- self.user_fback(Fd,Fd_tf)
+ self.user_feedback(Fd,Fd_tf)
# Populate msg variable
# Attitude control
@@ -495,7 +475,7 @@ class Main:
self.att_targ.orientation.z = q[2]
self.att_targ.orientation.w = q[3]
- def user_fback(self,F_noTransform, F_Transform):
+ def user_feedback(self,F_noTransform, F_Transform):
print('\n')
rospy.loginfo('thrust: %.6f' % self.att_targ.thrust)
rospy.loginfo('roll: %.2f pitch: %.2f',self.EulerAng[0]*180/3.14,self.EulerAng[1]*180/3.14)
diff --git a/src/mocap_offb_node.cpp b/src/mocap_offb_node.cpp
deleted file mode 100644
index ad53acc..0000000
--- a/src/mocap_offb_node.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/**
- * @file offb_node.cpp
- * @brief Offboard control example node, written with MAVROS version 0.19.x, PX4 Pro Flight
- * Stack and tested in Gazebo SITL
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-
-/********* CALLBACK FUNCTIONS **********************/
-// Initiate variables
-mavros_msgs::State current_state;
-geometry_msgs::PoseStamped desPose;
-
-// Callback function which will save the current state of the autopilot.
-// Allows to check connection, arming, and Offboard tags*/
-void state_cb(const mavros_msgs::State::ConstPtr& msg){
- current_state = *msg;
-}
-
-// Cb to recieve pose information
-// Initiate variables
-geometry_msgs::PoseStamped pose;
-geometry_msgs::Quaternion q_init;
-geometry_msgs::PoseStamped mavPose;
-bool pose_read = false;
-double current_altitude;
-
-void mavPose_cb(const geometry_msgs::PoseStamped::ConstPtr& msg){
- mavPose = *msg;
- current_altitude = mavPose.pose.position.z;
- while(pose_read == false){
- q_init = mavPose.pose.orientation;
- if(q_init.x == 0.0 && q_init.w == 0.0){
- ROS_INFO("Waiting...");
- } else {
- mavPose.pose.orientation.x = q_init.x;
- mavPose.pose.orientation.y = q_init.y;
- mavPose.pose.orientation.z = q_init.z;
- mavPose.pose.orientation.w = q_init.w;
- pose_read = true;
- }
- }
-
-}
-
-std_msgs::Bool connection_status;
-// bool connection_status
-// Determine if we are still receiving info from mocap and land if not
-void connection_cb(const std_msgs::Bool::ConstPtr& msg){
- connection_status = *msg;
-}
-
-int main(int argc, char **argv)
-{
- ros::init(argc, argv, "offb_node");
- ros::NodeHandle nh;
-
- /********************** SUBSCRIBERS **********************/
- // Get current state
- ros::Subscriber state_sub = nh.subscribe
- ("mavros/state", 10, state_cb);
-
- // Pose subscriber
- ros::Subscriber mavPose_sub = nh.subscribe
- ("mavros/local_position/pose",10,mavPose_cb);
-
- ros::Subscriber connection_sub = nh.subscribe
- ("/status/comms",10,connection_cb);
-
- // Waypoint Subscriber
- /*
- ros::Subscriber waypoint_sub = nh.subscribe
- ("/reference/waypoints",10,waypoints_cb);
- */
- /********************** PUBLISHERS **********************/
- // Initiate publisher to publish commanded local position
- ros::Publisher local_pos_pub = nh.advertise
- ("mavros/setpoint_position/local", 10);
-
- // Publish desired attitude
- ros::Publisher thrust_pub = nh.advertise
- ("mavros/setpoint_attitude/thrust", 10);
-
- // Publish attitude commands
- ros::Publisher att_pub = nh.advertise
- ("/mavros/setpoint_attitude/attitude",10);
-
- // Service Clients
- ros::ServiceClient arming_client = nh.serviceClient
- ("mavros/cmd/arming");
- ros::ServiceClient set_mode_client = nh.serviceClient
- ("mavros/set_mode");
- ros::ServiceClient takeoff_cl = nh.serviceClient
- ("mavros/cmd/takeoff");
- ros::ServiceClient waypoint_cl = nh.serviceClient
- ("status/waypoint_tracker");
-
- //the setpoint publishing rate MUST be faster than 2Hz... PX4 timeout = 500 ms
- ros::Rate rate(20.0);
-
- // wait for FCU connection
- while(ros::ok() && !current_state.connected){
- ros::spinOnce();
- rate.sleep();
- }
-
- // Retrieve desired waypoints
- oscillation_ctrl::WaypointTrack wpoint_srv;
- wpoint_srv.request.query = false;
- if (waypoint_cl.call(wpoint_srv))
- {
- ROS_INFO("Waypoints received");
- }
-
- // populate desired waypoints
- pose.pose.position.x = wpoint_srv.response.xd.x;
- pose.pose.position.y = wpoint_srv.response.xd.y;
- pose.pose.position.z = wpoint_srv.response.xd.z;
-
- //send a few setpoints before starting
- for(int i = 100; ros::ok() && i > 0; --i){
- local_pos_pub.publish(pose);
- ros::spinOnce();
- rate.sleep();
- }
-
- mavros_msgs::SetMode offb_set_mode;
- offb_set_mode.request.custom_mode = "OFFBOARD";
-
- mavros_msgs::CommandBool arm_cmd;
- arm_cmd.request.value = true;
-
- ros::Time last_request = ros::Time::now();
-
- while(ros::ok()){
- if(current_state.mode != "OFFBOARD" &&
- (ros::Time::now() - last_request > ros::Duration(7.0))){
- if( set_mode_client.call(offb_set_mode) &&
- offb_set_mode.response.mode_sent){
- ROS_INFO("OFFBOARD");
- }
- last_request = ros::Time::now();
- } else {
- if( !current_state.armed &&
- (ros::Time::now() - last_request > ros::Duration(3.0))){
- if(arming_client.call(arm_cmd) &&
- arm_cmd.response.success){
- ROS_INFO("ARMED");
- }
- last_request = ros::Time::now();
- }
- }
- // Update desired waypoints
- waypoint_cl.call(wpoint_srv);
- pose.pose.position.x = wpoint_srv.response.xd.x;
- pose.pose.position.y = wpoint_srv.response.xd.y;
- pose.pose.position.z = wpoint_srv.response.xd.z;
-
- // User info
- ROS_INFO("Current Altitude: %.2f",mavPose.pose.position.z);
- ROS_INFO("Desired Altitude: %.2f",pose.pose.position.z);
- ROS_INFO("---------------------------");
-
- // Check if we are still connected. Otherwise drone should be booted from offboard mode
- if(connection_status.data) {
- local_pos_pub.publish(pose);
- }
- else {
- ROS_INFO("Connection lost: landing drone...");
- }
-
- ros::spinOnce();
- rate.sleep();
- }
-
- return 0;
-}
-
-
diff --git a/src/mocap_runTest.py b/src/mocap_runTest.py
index fdbf9a0..77c87af 100755
--- a/src/mocap_runTest.py
+++ b/src/mocap_runTest.py
@@ -20,13 +20,23 @@ class Main:
self.get_xd = rospy.ServiceProxy('/status/waypoint_tracker',WaypointTrack)
# Set up desired waypoints for test
- self.xd = Point()
- self.xd.x = 0.0
- self.xd.y = 2.0
- self.xd.z = 1.5
+ self.xd1 = Point()
+ self.xd1.x = 0.0
+ self.xd1.y = -0.5
+ self.xd1.z = 1.75
+ self.xd2 = Point()
+ self.xd2.x = 0.0
+ self.xd2.y = 2.0
+ self.xd2.z = 1.75
+
# Determine if we want to run test with or without controller
+ ################# CHANGE THIS TO CHANGE TYPE Of TEST ###############################
+
self.change_mode = True # True = Change to oscillation damping mode after wait time
+ self.multiple_setpoins = True # True - will send multiple setpoints
+
+ #####################################################################################
if self.change_mode: self.loginfo_string = 'Attitude mode in...'
else: self.loginfo_string = 'Staying in Position mode.'
@@ -49,6 +59,7 @@ class Main:
""" Waits desired amount before setting UAV to appropriate mode, and then sets up desired waypoints"""
run_test = False
use_ctrl = False
+ waypoint_sent = False
while not run_test:
time_left = self.wait_time - (rospy.get_time() - self.tstart)
if not rospy.get_time() - self.tstart > self.wait_time:
@@ -58,14 +69,20 @@ class Main:
self.t_param = rospy.get_time()
use_ctrl = True
if use_ctrl:
- time_until_test = 7.0 - rospy.get_time() + self.t_param
- if not time_until_test <= 0.0:
- rospy.loginfo('In %.2f\nSending waypoints: x = %.2f y = %.2f z = %.2f',time_until_test,self.xd.x,self.xd.y,self.xd.z)
- else:
- self.set_waypoint(self.xd)
+ time_until_test1 = 25.0 - rospy.get_time() + self.t_param
+ time_until_test2 = 30.0 - rospy.get_time() + self.t_param
+ if time_until_test1 >= 0.0 and not waypoint_sent:
+ rospy.loginfo('In %.2f\nSending waypoints: x = %.2f y = %.2f z = %.2f',time_until_test1,self.xd1.x,self.xd1.y,self.xd1.z)
+ elif not waypoint_sent and time_until_test1 < 0.0:
+ waypoint_sent = True
+ self.set_waypoint(self.xd1)
+
+ if time_until_test2 >= 0.0 and waypoint_sent:
+ rospy.loginfo('In %.2f\nSending waypoints: x = %.2f y = %.2f z = %.2f',time_until_test2,self.xd2.x,self.xd2.y,self.xd2.z)
+ elif waypoint_sent and time_until_test2 < 0.0:
+ self.set_waypoint(self.xd2)
run_test = True
break
-
def set_waypoint(self,xd):
""" Set waypoints for oscillation controller """
diff --git a/src/offb_node.cpp b/src/offb_node.cpp
deleted file mode 100644
index 50cecbd..0000000
--- a/src/offb_node.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/**
- * @file offb_node.cpp
- * @brief Offboard control example node, written with MAVROS version 0.19.x, PX4 Pro Flight
- * Stack and tested in Gazebo SITL
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-
-/********* CALLBACK FUNCTIONS **********************/
-// Initiate variables
-mavros_msgs::State current_state;
-geometry_msgs::PoseStamped desPose;
-
-// Callback function which will save the current state of the autopilot.
-// Allows to check connection, arming, and Offboard tags*/
-void state_cb(const mavros_msgs::State::ConstPtr& msg){
- current_state = *msg;
-}
-
-// Cb to recieve pose information
-// Initiate variables
-geometry_msgs::PoseStamped pose;
-geometry_msgs::Quaternion q_init;
-geometry_msgs::PoseStamped mavPose;
-bool pose_read = false;
-double current_altitude;
-
-void mavPose_cb(const geometry_msgs::PoseStamped::ConstPtr& msg){
- mavPose = *msg;
- current_altitude = mavPose.pose.position.z;
- while(pose_read == false){
- q_init = mavPose.pose.orientation;
- if(q_init.x == 0.0 && q_init.w == 0.0){
- ROS_INFO("Waiting...");
- } else {
- pose_read = true;
- // pose.pose.orientation.x = q_init.x;
- // pose.pose.orientation.y = q_init.y;
- // pose.pose.orientation.z = q_init.z;
- // pose.pose.orientation.w = q_init.w;
- }
- }
-
-}
-
-int main(int argc, char **argv)
-{
- ros::init(argc, argv, "offb_node");
- ros::NodeHandle nh;
-
- /********************** SUBSCRIBERS **********************/
- // Get current state
- ros::Subscriber state_sub = nh.subscribe
- ("mavros/state", 10, state_cb);
-
- // Pose subscriber
- ros::Subscriber mavPose_sub = nh.subscribe
- ("mavros/local_position/pose",10,mavPose_cb);
-
- // Waypoint Subscriber
- /*
- ros::Subscriber waypoint_sub = nh.subscribe
- ("/reference/waypoints",10,waypoints_cb);
- */
- ros::ServiceClient waypoint_cl = nh.serviceClient
- ("status/waypoint_tracker");
-
- /********************** PUBLISHERS **********************/
- // Initiate publisher to publish commanded local position
- ros::Publisher local_pos_pub = nh.advertise
- ("mavros/setpoint_position/local", 10);
-
- // Publish desired attitude
- ros::Publisher thrust_pub = nh.advertise
- ("mavros/setpoint_attitude/thrust", 10);
-
- // Publish attitude commands
- ros::Publisher att_pub = nh.advertise
- ("/mavros/setpoint_attitude/attitude",10);
-
- // Service Clients
- ros::ServiceClient arming_client = nh.serviceClient
- ("mavros/cmd/arming");
- ros::ServiceClient set_mode_client = nh.serviceClient
- ("mavros/set_mode");
- ros::ServiceClient takeoff_cl = nh.serviceClient
- ("mavros/cmd/takeoff");
-
- //the setpoint publishing rate MUST be faster than 2Hz... PX4 timeout = 500 ms
- ros::Rate rate(20.0);
-
- // wait for FCU connection
- while(ros::ok() && !current_state.connected){
- ros::spinOnce();
- rate.sleep();
- }
-
- // Retrieve desired waypoints
- oscillation_ctrl::WaypointTrack wpoint_srv;
- wpoint_srv.request.query = false;
- if (waypoint_cl.call(wpoint_srv))
- {
- ROS_INFO("Waypoints received");
- }
-
- // populate desired waypoints
- pose.pose.position.x = wpoint_srv.response.xd.x;
- pose.pose.position.y = wpoint_srv.response.xd.y;
- pose.pose.position.z = wpoint_srv.response.xd.z;
-
- /*/ Populate pose msg
- pose.pose.orientation.x = q_init.x;
- pose.pose.orientation.y = q_init.y;
- pose.pose.orientation.z = q_init.z;
- pose.pose.orientation.w = q_init.w;
- */
-
- //send a few setpoints before starting
- for(int i = 100; ros::ok() && i > 0; --i){
- local_pos_pub.publish(pose);
- ros::spinOnce();
- rate.sleep();
- }
-
- mavros_msgs::SetMode offb_set_mode;
- offb_set_mode.request.custom_mode = "OFFBOARD";
-
- mavros_msgs::CommandBool arm_cmd;
- arm_cmd.request.value = true;
-
- ros::Time last_request = ros::Time::now();
-
- while(ros::ok()){
- if(current_state.mode != "OFFBOARD" &&
- (ros::Time::now() - last_request > ros::Duration(5.0))){
- if( set_mode_client.call(offb_set_mode) &&
- offb_set_mode.response.mode_sent){
- ROS_INFO("Offboard enabled");
- }
- last_request = ros::Time::now();
- } else {
- if( !current_state.armed &&
- (ros::Time::now() - last_request > ros::Duration(3.0))){
- if(arming_client.call(arm_cmd) &&
- arm_cmd.response.success){
- ROS_INFO("Vehicle armed");
- }
- last_request = ros::Time::now();
- }
- }
- // check if waypoints have changed desired waypoints
- waypoint_cl.call(wpoint_srv);
- pose.pose.position.x = wpoint_srv.response.xd.x;
- pose.pose.position.y = wpoint_srv.response.xd.y;
- pose.pose.position.z = wpoint_srv.response.xd.z;
-
- // User info
- ROS_INFO("Current Altitude: %.2f",mavPose.pose.position.z);
- ROS_INFO("Desired Altitude: %.2f",pose.pose.position.z);
- ROS_INFO("---------------------------");
-
- local_pos_pub.publish(pose);
-
- ros::spinOnce();
- rate.sleep();
- }
-
- return 0;
-}
-
-
diff --git a/src/path_follow.cpp b/src/path_follow.cpp
index 844ff7d..1b922f7 100644
--- a/src/path_follow.cpp
+++ b/src/path_follow.cpp
@@ -44,18 +44,18 @@ double current_altitude;
void mavPose_cb(const geometry_msgs::PoseStamped::ConstPtr& msg){
mavPose = *msg;
current_altitude = mavPose.pose.position.z;
- while(gps_read == false){
- q_init = mavPose.pose.orientation;
- if(q_init.x == 0.0 && q_init.w == 0.0){
- ROS_INFO("Waiting...");
- } else {
- buff_pose.pose.orientation.x = q_init.x;
- buff_pose.pose.orientation.y = q_init.y;
- buff_pose.pose.orientation.z = q_init.z;
- buff_pose.pose.orientation.w = q_init.w;
- gps_read = true;
- }
- }
+ // while(gps_read == false){
+ // q_init = mavPose.pose.orientation;
+ // if(q_init.x == 0.0 && q_init.w == 0.0){
+ // ROS_INFO("Waiting...");
+ // } else {
+ // buff_pose.pose.orientation.x = q_init.x;
+ // buff_pose.pose.orientation.y = q_init.y;
+ // buff_pose.pose.orientation.z = q_init.z;
+ // buff_pose.pose.orientation.w = q_init.w;
+ // gps_read = true;
+ // }
+ // }
}
int main(int argc, char **argv)
@@ -154,58 +154,47 @@ int main(int argc, char **argv)
double alt_des = wpoint_srv.response.xd.z; // Desired height
while(ros::ok()){
- if(gps_read == true){
- ROS_INFO("Entered while loop");
- if(current_state.mode != "OFFBOARD" && (ros::Time::now() - last_request > ros::Duration(5.0))){
- if( set_mode_client.call(offb_set_mode) && offb_set_mode.response.mode_sent){
- } else {
- ROS_INFO("Could not enter offboard mode");
- }
- //last_request = ros::Time::now();
+ if(current_state.mode != "OFFBOARD" && (ros::Time::now() - last_request > ros::Duration(5.0))){
+ if( set_mode_client.call(offb_set_mode) && offb_set_mode.response.mode_sent){
} else {
- if( !current_state.armed && (ros::Time::now() - last_request > ros::Duration(8.0))){
- if( arming_client.call(arm_cmd) && arm_cmd.response.success){
- ROS_INFO("Vehicle armed");
- }
- last_request = ros::Time::now();
+ ROS_INFO("Could not enter offboard mode");
+ }
+ } else {
+ if( !current_state.armed && (ros::Time::now() - last_request > ros::Duration(8.0))){
+ if( arming_client.call(arm_cmd) && arm_cmd.response.success){
+ ROS_INFO("Vehicle armed");
}
+ last_request = ros::Time::now();
}
-
- if(current_state.mode == "OFFBOARD" && current_state.armed){
- ROS_INFO_ONCE("Spiri is taking off");
- }
+ }
+
+ if(current_state.mode == "OFFBOARD" && current_state.armed){
+ ROS_INFO_ONCE("Spiri is taking off");
+ }
- // Check if we want to use oscillation controller
- //if (ros::param::get("/use_ctrl", oscillation_damp) == true){
- if (ros::param::has("/status/use_ctrl")){
- ros::param::get("/status/use_ctrl", oscillation_damp);
- if(oscillation_damp == true){
- ROS_INFO("ATTITUDE CTRL");
- att_targ.header.stamp = ros::Time::now();
- // Publish attitude commands
- att_targ_pub.publish(att_targ);
- } else {
- // Check if waypoints have changed
- // For attitude controller, ref_signalGen deals with changes
- // in desired waypoints, so we only check if not using controller
- if (waypoint_cl.call(wpoint_srv))
- {
- // populate desired waypoints
- buff_pose.pose.position.x = wpoint_srv.response.xd.x;
- buff_pose.pose.position.y = wpoint_srv.response.xd.y;
- buff_pose.pose.position.z = wpoint_srv.response.xd.z;
- }
- ROS_INFO("POSITION CTRL");
- // Publish position setpoints
- local_pos_pub.publish(buff_pose);
- }
+ // Check if we want to use oscillation controller
+ if (ros::param::has("/status/use_ctrl")){
+ ros::param::get("/status/use_ctrl", oscillation_damp);
+ if(oscillation_damp == true){
+ ROS_INFO("ATTITUDE CTRL");
+ att_targ.header.stamp = ros::Time::now();
+ // Publish attitude commands
+ att_targ_pub.publish(att_targ);
+ } else {
+ ROS_INFO("POSITION CTRL");
+ //ROS_INFO("POSITION CTRL");
+ // Publish position setpoints
+ local_pos_pub.publish(buff_pose);
}
- ROS_INFO("Des Altitude: %.2f", alt_des);
+ ROS_INFO("Des Altitude: %.2f", wpoint_srv.response.xd.z);
ROS_INFO("Cur Altitude: %.2f", current_altitude);
ROS_INFO("---------------------------");
- ros::spinOnce();
- rate_pub.sleep();
+ } else {
+ ROS_WARN("CONTROL PARAM NOT FOUND. PLEASE SET '/status/use_ctrl'");
}
+
+ ros::spinOnce();
+ rate_pub.sleep();
}
return 0;
diff --git a/src/ref_signalGen.py b/src/ref_signalGen.py
index 03d3d7c..a3d71e0 100755
--- a/src/ref_signalGen.py
+++ b/src/ref_signalGen.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python
### Cesar Rodriguez July 2021
### Based off of Klausen 2017 - Smooth trajectory generation based on desired waypoints
@@ -10,11 +10,10 @@ import math
import rosservice
from scipy.integrate import odeint
-from oscillation_ctrl.msg import RefSignal, LoadAngles, TetheredStatus
+from oscillation_ctrl.msg import RefSignal, LoadAngles
from oscillation_ctrl.srv import WaypointTrack
from geometry_msgs.msg import Pose, PoseStamped, Point, TwistStamped
from sensor_msgs.msg import Imu
-from mavros_msgs.msg import State
class DesiredPoint():
def __init__(self,x,y,z):
@@ -38,12 +37,11 @@ class Main:
self.tmax = self.dt # used to get desired pos, vel, and acc for next time step (tmax)
self.n = self.tmax/self.dt + 1
self.t = np.linspace(0, self.tmax, self.n) # Time array
- # self.t = np.linspace(0, 1.0, 10) # Time array
# Message generation/ collection
self.vel_data = TwistStamped() # This is needed to get drone vel from gps
- self.imu_data = Imu() # Needed for to get drone acc from IMU
- self.ref_sig = RefSignal() # Smooth Signal
+ self.imu_data = Imu() # Needed for to get drone acc from IMU
+ self.ref_sig = RefSignal() # Smooth Signal
self.load_angles = LoadAngles()
self.has_run = 0 # Bool to keep track of first run instance
@@ -58,7 +56,6 @@ class Main:
# Topic, msg type, and class callback method
rospy.Subscriber('/status/load_angles', LoadAngles, self.loadAngles_cb)
rospy.Subscriber('/mavros/local_position/pose', PoseStamped, self.dronePos_cb)
- # rospy.Subscriber('/status/twoBody_status', TetheredStatus, self.dronePos_cb)
rospy.Subscriber('/mavros/local_position/velocity_body', TwistStamped, self.droneVel_cb)
rospy.Subscriber('/mavros/imu/data', Imu, self.droneAcc_cb)
@@ -67,8 +64,7 @@ class Main:
# --------------------------------------------------------------------------------#
# Publish desired path to compute attitudes
self.pub_path = rospy.Publisher('/reference/path',RefSignal,queue_size = 10)
- # Needed for geometric controller to compute thrust
- #self.pub_ref = rospy.Publisher('/reference/flatsetpoint',FlatTarget,queue_size = 10)
+ self.waypointTracker_pub = rospy.Publisher('/reference/waypoints',Point,queue_size = 10) # not needed. Used for performance analysis
# timer(s), used to control method loop freq(s) as defined by the rate(s)
self.pub_tim = rospy.Timer(rospy.Duration(1.0/rate), self.publisher)
@@ -82,7 +78,7 @@ class Main:
self.EPS_I = np.zeros(9) # Epsilon shapefilter
# Constants for smooth path generation
- self.w_tune = 1 # also works well :) 3.13 works well? #########################################################################
+ self.w_tune = 1 # Increase this to increase aggresiveness of trajectory i.e. higher accelerations
self.epsilon = 0.7 # Damping ratio
# need exception if we do not have tether:
@@ -330,9 +326,6 @@ class Main:
self.sigmoid() # Determine sigmoid gain
EPS_D = self.fback() # Feedback Epsilon
- # for i in range(9):
- # Populate EPS_F buffer with desired change based on feedback
- # self.EPS_F[i] = self.EPS_I[i] + self.s_gain*EPS_D[i] #+ EPS_D[i]
self.EPS_F = self.EPS_I + self.s_gain*EPS_D
# Populate msg with epsilon_final
@@ -340,22 +333,14 @@ class Main:
#self.ref_sig.type_mask = 2 # Need typemask = 2 to use correct attitude controller - Jaeyoung Lin
self.ref_sig.position.x = self.EPS_F[0]
self.ref_sig.position.y = self.EPS_F[1]
+ self.ref_sig.position.z = self.EPS_F[2]
self.ref_sig.velocity.x = self.EPS_F[3]
self.ref_sig.velocity.y = self.EPS_F[4]
+ self.ref_sig.velocity.z = self.EPS_F[5]
self.ref_sig.acceleration.x = self.EPS_F[6]
self.ref_sig.acceleration.y = self.EPS_F[7]
-
- # Do not need to evaluate z
- # self.ref_sig.position.z = self.xd.z
- # self.ref_sig.velocity.z = 0.0
- # self.ref_sig.acceleration.z = 0.0
- self.ref_sig.position.z = self.EPS_F[2]
- self.ref_sig.velocity.z = self.EPS_F[5]
self.ref_sig.acceleration.z = self.EPS_F[8]
-
- # self.x0 = [self.dr_pos.position.x, self.x[1,1], self.x[1,2], self.x[1,3]]
- # self.y0 = [self.dr_pos.position.y, self.y[1,1], self.y[1,2], self.y[1,3]]
- # self.z0 = [self.dr_pos.position.z, self.z[1,1], self.z[1,2], self.z[1,3]]
+
self.x0 = [self.x[1,0], self.x[1,1], self.x[1,2], self.x[1,3]]
self.y0 = [self.y[1,0], self.y[1,1], self.y[1,2], self.y[1,3]]
self.z0 = [self.z[1,0], self.z[1,1], self.z[1,2], self.z[1,3]]
@@ -379,7 +364,7 @@ class Main:
return EPS_D
- def user_fback(self):
+ def user_feeback(self):
# Feedback to user
rospy.loginfo(' Var | x | y | z ')
@@ -387,9 +372,7 @@ class Main:
rospy.loginfo('Vel: %.2f %.2f %.2f',self.EPS_F[3],self.EPS_F[4],self.EPS_F[5])
rospy.loginfo('Acc: %.2f %.2f %.2f',self.EPS_F[6],self.EPS_F[7],self.EPS_F[8])
rospy.loginfo('_______________________')
- # rospy.loginfo_once('Tether length: %.2f',self.tetherL)
- # rospy.loginfo('Theta: %.2f',self.load_angles.theta)
- # rospy.loginfo('Phi: %.2f',self.load_angles.phi)
+
def publisher(self,pub_tim):
@@ -399,8 +382,11 @@ class Main:
# Publish reference signal
self.pub_path.publish(self.ref_sig)
+ # Publish what the setpoints are
+ self.waypointTracker_pub.publish(self.xd)
+
# Give user feedback on published message:
- self.user_fback()
+ self.user_feeback()
if __name__=="__main__":
diff --git a/src/set_ploadmass.py b/src/set_ploadmass.py
new file mode 100755
index 0000000..347ef17
--- /dev/null
+++ b/src/set_ploadmass.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python2.7
+
+### Cesar Rodriguez Sept 2022
+### changes pload mass depending on /status/pload_mass parameter
+
+import rospy
+import rosservice
+from gazebo_msgs.srv import GetLinkProperties, SetLinkProperties
+
+class Main:
+ def __init__(self):
+ # Variables needed for testing start
+
+ # link (payload) name
+ self.link_name = 'spiri_with_tether::mass::payload'
+
+ # service names we will use
+ self.service_request = '/gazebo/get_link_properties'
+ self.service_call = '/gazebo/set_link_properties'
+
+ # wait for service
+ rospy.wait_for_service(self.service_request)
+ # set up service request
+ get_link_properties = rospy.ServiceProxy(self.service_request,GetLinkProperties)
+ # wait for service to set link properties
+ rospy.wait_for_service(self.service_call)
+ # set up service request
+ set_link_properties = rospy.ServiceProxy(self.service_call,SetLinkProperties)
+
+ # get payload properties
+ self.pload_properties = get_link_properties(self.link_name)
+
+ # state parameter name for where payload mass is stored
+ self.param_pload_mass = 'status/pload_mass'
+
+ # check if parameter exists
+ if rospy.has_param(self.param_pload_mass):
+ self.desired_mass = rospy.get_param(self.param_pload_mass) # get desired mass
+ try:
+ # set desired mass and necessary inertial properties
+ set_link_properties(link_name=self.link_name,mass=self.desired_mass,
+ ixx=self.pload_properties.ixx,iyy=self.pload_properties.iyy,izz=self.pload_properties.izz,
+ gravity_mode=self.pload_properties.gravity_mode)
+ rospy.loginfo('Set payload mass to: %.3f', self.desired_mass)
+ except rospy.ServiceException as e:
+ rospy.loginfo("Set Link State call failed: {0}".format(e))
+ else: rospy.logwarn('COULD NOT FIND PLOAD MASS PARAM')
+
+if __name__=="__main__":
+
+ # Initiate ROS node
+ rospy.init_node('MoCap_node',anonymous=False)
+ try:
+ Main() # create class object
+ rospy.spin() # loop until shutdown signal
+
+ except rospy.ROSInterruptException:
+ pass
+
diff --git a/src/thrust_controller.py b/src/thrust_controller.py
deleted file mode 100755
index 0c56345..0000000
--- a/src/thrust_controller.py
+++ /dev/null
@@ -1,173 +0,0 @@
-#!/usr/bin/env python2.7
-
-### Cesar Rodriguez Sept 21
-### Used to control thrust of drone
-
-import rospy, tf
-import numpy as np
-
-from geometry_msgs.msg import PoseStamped, TwistStamped
-from mavros_msgs.msg import AttitudeTarget
-
-class PID:
- def __init__(self):
- # rate(s)
- rate = 35.0
- self.dt = 1/rate
- # Variables needed for testing start
- self.tstart = rospy.get_time() # Keep track of the start time
- while self.tstart == 0.0: # Need to make sure get_rostime works
- self.tstart = rospy.get_time()
-
- # tuning gains
- #self.Kp = 0.335
- #self.Kd = 0.1
- self.Kp = 2.7
- self.Kd = 0.5
-
- # drone var
- self.drone_m = 1.437
- self.max_a = 14.2
- self.max_t = self.drone_m*self.max_a
-
- # message variables
- self.pose = PoseStamped()
- self.pose_buff = PoseStamped()
- self.pose_buff.pose.position.z = 2.5
-
- self.attitude = AttitudeTarget()
- self.attitude.type_mask = 1|2|4 # ignore body rate command
- self.attitude.orientation.x = 0.0
- self.attitude.orientation.y = 0.0
- self.attitude.orientation.z = 0.0
- self.attitude.orientation.w = 1.0
-
- self.des_alt = 2.5
- self.dr_vel = TwistStamped()
- #self.cur_att = PoseStamped()
- self.R = np.empty([3,3])
-
- # clients
-
-
- # subscribers
- rospy.Subscriber('/mavros/local_position/pose',PoseStamped, self.pose_cb)
- rospy.Subscriber('/mavros/local_position/velocity_local', TwistStamped, self.droneVel_cb)
-
- # publishers
- self.pub_attitude = rospy.Publisher('/command/thrust', AttitudeTarget, queue_size=10)
-
-
- # publishing rate
- self.pub_time = rospy.Timer(rospy.Duration(1.0/rate), self.publisher)
-
- def pose_cb(self,msg):
- self.cur_alt = msg.pose.position.z
-
- self.pose = msg
-
- # Callback for drone velocity
- def droneVel_cb(self,msg):
- try:
- self.dr_vel = msg
-
- except ValueError or TypeError:
- pass
-
-
- def quaternion_rotation_matrix(self):
- """
- Covert a quaternion into a full three-dimensional rotation matrix.
-
- Input
- :param Q: A 4 element array representing the quaternion (q0,q1,q2,q3)
-
- Output
- :return: A 3x3 element matrix representing the full 3D rotation matrix.
- This rotation matrix converts a point in the local reference
- frame to a point in the global reference frame.
- """
- # Extract the values from Q
- q0 = self.pose.pose.orientation.w
- q1 = self.pose.pose.orientation.x
- q2 = self.pose.pose.orientation.y
- q3 = self.pose.pose.orientation.z
-
- # First row of the rotation matrix
- r00 = 2 * (q0 * q0 + q1 * q1) - 1
- r01 = 2 * (q1 * q2 - q0 * q3)
- r02 = 2 * (q1 * q3 + q0 * q2)
-
- # Second row of the rotation matrix
- r10 = 2 * (q1 * q2 + q0 * q3)
- r11 = 2 * (q0 * q0 + q2 * q2) - 1
- r12 = 2 * (q2 * q3 - q0 * q1)
-
- # Third row of the rotation matrix
- r20 = 2 * (q1 * q3 - q0 * q2)
- r21 = 2 * (q2 * q3 + q0 * q1)
- r22 = 2 * (q0 * q0 + q3 * q3) - 1
-
- # 3x3 rotation matrix
- rot_matrix = np.array([[r00, r01, r02],
- [r10, r11, r12],
- [r20, r21, r22]])
-
- return rot_matrix
-
- def operation(self):
- self.error = self.cur_alt - self.des_alt # error in z dir.
- self.R = self.quaternion_rotation_matrix() # determine Rotation Matrix
-
- # thrust as per Geometric Tracking Control of a Quadrotor UAV on SE(3)
- # Taeyoung Lee, Melvin Leok, and N. Harris McClamroch
- thrust = np.dot(9.81*self.drone_m -self.Kp*self.error -self.Kd*self.dr_vel.twist.linear.z,self.R.T[2])/self.max_t
- self.attitude.thrust = thrust[2] # save thurst in z-dir
-
- # Value needs to be between 0 - 1.0
- if self.attitude.thrust >= 1.0:
- self.attitude.thrust = 1.0
- elif self.attitude.thrust <= 0.0:
- self.attitude.thrust = 0.0
-
-
- def publisher(self,pub_time):
- self.operation() # determine thrust
- self.attitude.header.stamp = rospy.Time.now()
- self.pub_attitude.publish(self.attitude)
-
- def user_feedback(self):
- rospy.loginfo('Des: %.2f',self.des_alt)
- rospy.loginfo('Error: %.2f',self.error)
- rospy.loginfo('Throttle: %f\n',self.attitude.thrust)
-
-if __name__=="__main__":
-
- # Initiate ROS node
- rospy.init_node('thrust_PID')
- try:
- PID() # create class object
-
- rospy.spin() # loop until shutdown signal
-
- except rospy.ROSInterruptException:
- pass
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-