Added service to set waypoints
This commit is contained in:
parent
0c0764387b
commit
4fbed7a57c
|
@ -0,0 +1,270 @@
|
||||||
|
# Common configuration for PX4 autopilot
|
||||||
|
#
|
||||||
|
# node:
|
||||||
|
startup_px4_usb_quirk: true
|
||||||
|
|
||||||
|
# --- system plugins ---
|
||||||
|
|
||||||
|
# sys_status & sys_time connection options
|
||||||
|
conn:
|
||||||
|
heartbeat_rate: 1.0 # send hertbeat rate in Hertz
|
||||||
|
timeout: 10.0 # hertbeat timeout in seconds
|
||||||
|
timesync_rate: 10.0 # TIMESYNC rate in Hertz (feature disabled if 0.0)
|
||||||
|
system_time_rate: 1.0 # send system time to FCU rate in Hertz (disabled if 0.0)
|
||||||
|
|
||||||
|
# sys_status
|
||||||
|
sys:
|
||||||
|
min_voltage: 10.0 # diagnostics min voltage
|
||||||
|
disable_diag: false # disable all sys_status diagnostics, except heartbeat
|
||||||
|
|
||||||
|
# sys_time
|
||||||
|
time:
|
||||||
|
time_ref_source: "fcu" # time_reference source
|
||||||
|
timesync_mode: MAVLINK
|
||||||
|
timesync_avg_alpha: 0.6 # timesync averaging factor
|
||||||
|
|
||||||
|
# --- mavros plugins (alphabetical order) ---
|
||||||
|
|
||||||
|
# 3dr_radio
|
||||||
|
tdr_radio:
|
||||||
|
low_rssi: 40 # raw rssi lower level for diagnostics
|
||||||
|
|
||||||
|
# actuator_control
|
||||||
|
# None
|
||||||
|
|
||||||
|
# command
|
||||||
|
cmd:
|
||||||
|
use_comp_id_system_control: false # quirk for some old FCUs
|
||||||
|
|
||||||
|
# dummy
|
||||||
|
# None
|
||||||
|
|
||||||
|
# ftp
|
||||||
|
# None
|
||||||
|
|
||||||
|
# global_position
|
||||||
|
global_position:
|
||||||
|
frame_id: "map" # origin frame
|
||||||
|
child_frame_id: "base_link" # body-fixed frame
|
||||||
|
rot_covariance: 99999.0 # covariance for attitude?
|
||||||
|
gps_uere: 1.0 # User Equivalent Range Error (UERE) of GPS sensor (m)
|
||||||
|
use_relative_alt: true # use relative altitude for local coordinates
|
||||||
|
tf:
|
||||||
|
send: false # send TF?
|
||||||
|
frame_id: "map" # TF frame_id
|
||||||
|
global_frame_id: "earth" # TF earth frame_id
|
||||||
|
child_frame_id: "base_link" # TF child_frame_id
|
||||||
|
|
||||||
|
# imu_pub
|
||||||
|
imu:
|
||||||
|
frame_id: "base_link"
|
||||||
|
# need find actual values
|
||||||
|
linear_acceleration_stdev: 0.0003
|
||||||
|
angular_velocity_stdev: 0.0003490659 // 0.02 degrees
|
||||||
|
orientation_stdev: 1.0
|
||||||
|
magnetic_stdev: 0.0
|
||||||
|
|
||||||
|
# local_position
|
||||||
|
local_position:
|
||||||
|
frame_id: "map"
|
||||||
|
tf:
|
||||||
|
send: false
|
||||||
|
frame_id: "map"
|
||||||
|
child_frame_id: "base_link"
|
||||||
|
send_fcu: false
|
||||||
|
|
||||||
|
# param
|
||||||
|
# None, used for FCU params
|
||||||
|
|
||||||
|
# rc_io
|
||||||
|
# None
|
||||||
|
|
||||||
|
# safety_area
|
||||||
|
safety_area:
|
||||||
|
p1: {x: 1.0, y: 1.0, z: 1.0}
|
||||||
|
p2: {x: -1.0, y: -1.0, z: -1.0}
|
||||||
|
|
||||||
|
# setpoint_accel
|
||||||
|
setpoint_accel:
|
||||||
|
send_force: false
|
||||||
|
|
||||||
|
# setpoint_attitude
|
||||||
|
setpoint_attitude:
|
||||||
|
reverse_thrust: false # allow reversed thrust
|
||||||
|
use_quaternion: true # enable PoseStamped topic subscriber
|
||||||
|
tf:
|
||||||
|
listen: false # enable tf listener (disable topic subscribers)
|
||||||
|
frame_id: "map"
|
||||||
|
child_frame_id: "target_attitude"
|
||||||
|
rate_limit: 50.0
|
||||||
|
|
||||||
|
setpoint_raw:
|
||||||
|
thrust_scaling: 1.0 # used in setpoint_raw attitude callback.
|
||||||
|
# Note: PX4 expects normalized thrust values between 0 and 1, which means that
|
||||||
|
# the scaling needs to be unitary and the inputs should be 0..1 as well.
|
||||||
|
|
||||||
|
# setpoint_position
|
||||||
|
setpoint_position:
|
||||||
|
tf:
|
||||||
|
listen: false # enable tf listener (disable topic subscribers)
|
||||||
|
frame_id: "map"
|
||||||
|
child_frame_id: "target_position"
|
||||||
|
rate_limit: 50.0
|
||||||
|
mav_frame: LOCAL_NED
|
||||||
|
|
||||||
|
# setpoint_velocity
|
||||||
|
setpoint_velocity:
|
||||||
|
mav_frame: LOCAL_NED
|
||||||
|
|
||||||
|
# vfr_hud
|
||||||
|
# None
|
||||||
|
|
||||||
|
# waypoint
|
||||||
|
mission:
|
||||||
|
pull_after_gcs: true # update mission if gcs updates
|
||||||
|
|
||||||
|
# --- mavros extras plugins (same order) ---
|
||||||
|
|
||||||
|
# adsb
|
||||||
|
# None
|
||||||
|
|
||||||
|
# debug_value
|
||||||
|
# None
|
||||||
|
|
||||||
|
# distance_sensor
|
||||||
|
## Currently available orientations:
|
||||||
|
# Check http://wiki.ros.org/mavros/Enumerations
|
||||||
|
##
|
||||||
|
distance_sensor:
|
||||||
|
hrlv_ez4_pub:
|
||||||
|
id: 0
|
||||||
|
frame_id: "hrlv_ez4_sonar"
|
||||||
|
orientation: PITCH_270 # RPY:{0.0, 270.0, 0.0} - downward-facing
|
||||||
|
field_of_view: 0.0 # XXX TODO
|
||||||
|
send_tf: true
|
||||||
|
sensor_position: {x: 0.0, y: 0.0, z: -0.1}
|
||||||
|
lidarlite_pub:
|
||||||
|
id: 1
|
||||||
|
frame_id: "lidarlite_laser"
|
||||||
|
orientation: PITCH_270
|
||||||
|
field_of_view: 0.0 # XXX TODO
|
||||||
|
send_tf: true
|
||||||
|
sensor_position: {x: 0.0, y: 0.0, z: -0.1}
|
||||||
|
sonar_1_sub:
|
||||||
|
subscriber: true
|
||||||
|
id: 2
|
||||||
|
orientation: PITCH_270
|
||||||
|
laser_1_sub:
|
||||||
|
subscriber: true
|
||||||
|
id: 3
|
||||||
|
orientation: PITCH_270
|
||||||
|
|
||||||
|
# image_pub
|
||||||
|
image:
|
||||||
|
frame_id: "px4flow"
|
||||||
|
|
||||||
|
# fake_gps
|
||||||
|
fake_gps:
|
||||||
|
# select data source
|
||||||
|
use_mocap: true # ~mocap/pose
|
||||||
|
mocap_transform: false # ~mocap/tf instead of pose
|
||||||
|
use_vision: false # ~vision (pose)
|
||||||
|
# origin (default: Zürich)
|
||||||
|
geo_origin:
|
||||||
|
lat: 47.3667 # latitude [degrees]
|
||||||
|
lon: 8.5500 # longitude [degrees]
|
||||||
|
alt: 408.0 # altitude (height over the WGS-84 ellipsoid) [meters]
|
||||||
|
eph: 2.0
|
||||||
|
epv: 2.0
|
||||||
|
satellites_visible: 5 # virtual number of visible satellites
|
||||||
|
fix_type: 3 # type of GPS fix (default: 3D)
|
||||||
|
tf:
|
||||||
|
listen: false
|
||||||
|
send: false # send TF?
|
||||||
|
frame_id: "map" # TF frame_id
|
||||||
|
child_frame_id: "fix" # TF child_frame_id
|
||||||
|
rate_limit: 10.0 # TF rate
|
||||||
|
gps_rate: 5.0 # GPS data publishing rate
|
||||||
|
|
||||||
|
# landing_target
|
||||||
|
landing_target:
|
||||||
|
listen_lt: false
|
||||||
|
mav_frame: "LOCAL_NED"
|
||||||
|
land_target_type: "VISION_FIDUCIAL"
|
||||||
|
image:
|
||||||
|
width: 640 # [pixels]
|
||||||
|
height: 480
|
||||||
|
camera:
|
||||||
|
fov_x: 2.0071286398 # default: 115 [degrees]
|
||||||
|
fov_y: 2.0071286398
|
||||||
|
tf:
|
||||||
|
send: true
|
||||||
|
listen: false
|
||||||
|
frame_id: "landing_target"
|
||||||
|
child_frame_id: "camera_center"
|
||||||
|
rate_limit: 10.0
|
||||||
|
target_size: {x: 0.3, y: 0.3}
|
||||||
|
|
||||||
|
# mocap_pose_estimate
|
||||||
|
mocap:
|
||||||
|
# select mocap source
|
||||||
|
use_tf: false # ~mocap/tf
|
||||||
|
use_pose: true # ~mocap/pose
|
||||||
|
|
||||||
|
# odom
|
||||||
|
odometry:
|
||||||
|
in:
|
||||||
|
frame_id: "odom"
|
||||||
|
child_frame_id: "base_link"
|
||||||
|
frame_tf:
|
||||||
|
local_frame: "local_origin_ned"
|
||||||
|
body_frame_orientation: "flu"
|
||||||
|
out:
|
||||||
|
frame_tf:
|
||||||
|
# available: check MAV_FRAME odometry local frames in
|
||||||
|
# https://mavlink.io/en/messages/common.html
|
||||||
|
local_frame: "vision_ned"
|
||||||
|
# available: ned, frd or flu (though only the tf to frd is supported)
|
||||||
|
body_frame_orientation: "frd"
|
||||||
|
|
||||||
|
# px4flow
|
||||||
|
px4flow:
|
||||||
|
frame_id: "px4flow"
|
||||||
|
ranger_fov: 0.118682 # 6.8 degrees at 5 meters, 31 degrees at 1 meter
|
||||||
|
ranger_min_range: 0.3 # meters
|
||||||
|
ranger_max_range: 5.0 # meters
|
||||||
|
|
||||||
|
# vision_pose_estimate
|
||||||
|
vision_pose:
|
||||||
|
tf:
|
||||||
|
listen: false # enable tf listener (disable topic subscribers)
|
||||||
|
frame_id: "map"
|
||||||
|
child_frame_id: "vision_estimate"
|
||||||
|
rate_limit: 10.0
|
||||||
|
|
||||||
|
# vision_speed_estimate
|
||||||
|
vision_speed:
|
||||||
|
listen_twist: true # enable listen to twist topic, else listen to vec3d topic
|
||||||
|
twist_cov: true # enable listen to twist with covariance topic
|
||||||
|
|
||||||
|
# vibration
|
||||||
|
vibration:
|
||||||
|
frame_id: "base_link"
|
||||||
|
|
||||||
|
# wheel_odometry
|
||||||
|
wheel_odometry:
|
||||||
|
count: 2 # number of wheels to compute odometry
|
||||||
|
use_rpm: false # use wheel's RPM instead of cumulative distance to compute odometry
|
||||||
|
wheel0: {x: 0.0, y: -0.15, radius: 0.05} # x-, y-offset (m,NED) and radius (m)
|
||||||
|
wheel1: {x: 0.0, y: 0.15, radius: 0.05} # x-, y-offset (m,NED) and radius (m)
|
||||||
|
send_raw: true # send wheel's RPM and cumulative distance (~/wheel_odometry/rpm, ~/wheel_odometry/distance)
|
||||||
|
send_twist: false # send geometry_msgs/TwistWithCovarianceStamped instead of nav_msgs/Odometry
|
||||||
|
frame_id: "map" # origin frame
|
||||||
|
child_frame_id: "base_link" # body-fixed frame
|
||||||
|
vel_error: 0.1 # wheel velocity measurement error 1-std (m/s)
|
||||||
|
tf:
|
||||||
|
send: true
|
||||||
|
frame_id: "map"
|
||||||
|
child_frame_id: "base_link"
|
||||||
|
|
||||||
|
# vim:set ts=2 sw=2 et:
|
|
@ -0,0 +1,15 @@
|
||||||
|
plugin_blacklist:
|
||||||
|
# common
|
||||||
|
- safety_area
|
||||||
|
# extras
|
||||||
|
- image_pub
|
||||||
|
- vibration
|
||||||
|
- distance_sensor
|
||||||
|
- rangefinder
|
||||||
|
- wheel_odometry
|
||||||
|
- mission
|
||||||
|
- tdr_radio
|
||||||
|
- fake_gps
|
||||||
|
|
||||||
|
plugin_whitelist: []
|
||||||
|
#- 'sys_*'
|
|
@ -1,9 +0,0 @@
|
||||||
digraph G {
|
|
||||||
"local_origin" -> "local_origin_ned"[label="Broadcaster: /mavros\nAverage rate: 10000.000 Hz\nMost recent transform: 0.000 ( 124.428 sec old)\nBuffer length: 0.000 sec\n"];
|
|
||||||
"fcu" -> "fcu_frd"[label="Broadcaster: /mavros\nAverage rate: 10000.000 Hz\nMost recent transform: 0.000 ( 124.428 sec old)\nBuffer length: 0.000 sec\n"];
|
|
||||||
"fcu_frd" -> "fcu"[label="Broadcaster: /mavros\nAverage rate: 10000.000 Hz\nMost recent transform: 0.000 ( 124.428 sec old)\nBuffer length: 0.000 sec\n"];
|
|
||||||
edge [style=invis];
|
|
||||||
subgraph cluster_legend { style=bold; color=black; label ="view_frames Result";
|
|
||||||
"Recorded at time: 124.428"[ shape=plaintext ] ;
|
|
||||||
}->"local_origin";
|
|
||||||
}
|
|
BIN
frames.pdf
BIN
frames.pdf
Binary file not shown.
|
@ -14,6 +14,7 @@ Launch file to use klausen oscillaton damping ctrl in Gazebo
|
||||||
pkg="oscillation_ctrl"
|
pkg="oscillation_ctrl"
|
||||||
type="MoCap_Localization_noTether.py"
|
type="MoCap_Localization_noTether.py"
|
||||||
name="localize_node"
|
name="localize_node"
|
||||||
|
launch-prefix="xterm -e"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Cortex bridge launch -->
|
<!-- Cortex bridge launch -->
|
||||||
|
@ -21,4 +22,6 @@ Launch file to use klausen oscillaton damping ctrl in Gazebo
|
||||||
|
|
||||||
<!-- MAVROS launch -->
|
<!-- MAVROS launch -->
|
||||||
<include file="$(find mavros)/launch/px4.launch"/>
|
<include file="$(find mavros)/launch/px4.launch"/>
|
||||||
|
<arg name="pluginlists_yaml" value="$(find oscillation_ctrl)/config/px4_pluginlists.yaml" />
|
||||||
|
<arg name="config_yaml" value="$(find oscillation_ctrl)/config/px4_config.yaml" />
|
||||||
</launch>
|
</launch>
|
||||||
|
|
|
@ -22,6 +22,11 @@ Launch file to use klausen oscillaton damping ctrl in Gazebo
|
||||||
name="linkStates_node"
|
name="linkStates_node"
|
||||||
launch-prefix="xterm -e"
|
launch-prefix="xterm -e"
|
||||||
/>
|
/>
|
||||||
|
<node
|
||||||
|
pkg="oscillation_ctrl"
|
||||||
|
type="wpoint_tracker.py"
|
||||||
|
name="waypoints_server"
|
||||||
|
/>
|
||||||
<node
|
<node
|
||||||
pkg="oscillation_ctrl"
|
pkg="oscillation_ctrl"
|
||||||
type="ref_signalGen.py"
|
type="ref_signalGen.py"
|
||||||
|
|
|
@ -11,7 +11,6 @@ from tf.transformations import *
|
||||||
from offboard_ex.msg import tethered_status
|
from offboard_ex.msg import tethered_status
|
||||||
from geometry_msgs.msg import Pose
|
from geometry_msgs.msg import Pose
|
||||||
from gazebo_msgs.srv import GetLinkState
|
from gazebo_msgs.srv import GetLinkState
|
||||||
from oscillation_ctrl.srv import WaypointTrack
|
|
||||||
from std_msgs.msg import Bool
|
from std_msgs.msg import Bool
|
||||||
|
|
||||||
class Main:
|
class Main:
|
||||||
|
@ -53,6 +52,9 @@ class Main:
|
||||||
self.phidot_max = 3.0
|
self.phidot_max = 3.0
|
||||||
self.thetadot_max = 3.0
|
self.thetadot_max = 3.0
|
||||||
|
|
||||||
|
# Vehicle is spawned with yaw offset for convenience, need to deal with that
|
||||||
|
self.yaw_offset = 0.0
|
||||||
|
|
||||||
# variables for message gen
|
# variables for message gen
|
||||||
self.status = tethered_status()
|
self.status = tethered_status()
|
||||||
self.status.drone_id = 'spiri_with_tether::spiri::base'
|
self.status.drone_id = 'spiri_with_tether::spiri::base'
|
||||||
|
@ -97,18 +99,18 @@ class Main:
|
||||||
output = value
|
output = value
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def euler_array(self,pose):
|
def euler_array(self,orientation):
|
||||||
"""
|
"""
|
||||||
Takes in pose msg object and outputs array of euler angs:
|
Takes in pose msg object and outputs array of euler angs:
|
||||||
q[0] = Roll
|
eul[0] = Roll
|
||||||
q[1] = Pitch
|
eul[1] = Pitch
|
||||||
q[2] = Yaw
|
eul[2] = Yaw
|
||||||
"""
|
"""
|
||||||
q = euler_from_quaternion([pose.orientation.x,
|
eul = euler_from_quaternion([orientation.x,
|
||||||
pose.orientation.y,
|
orientation.y,
|
||||||
pose.orientation.z,
|
orientation.z,
|
||||||
pose.orientation.w])
|
orientation.w])
|
||||||
return q
|
return eul
|
||||||
|
|
||||||
# Get link states (drone and pload) and determine angle between them
|
# Get link states (drone and pload) and determine angle between them
|
||||||
def link_state(self,pub_timer):
|
def link_state(self,pub_timer):
|
||||||
|
@ -125,9 +127,9 @@ class Main:
|
||||||
# P = Position vector
|
# P = Position vector
|
||||||
drone_P = get_P(self.status.drone_id,reference)
|
drone_P = get_P(self.status.drone_id,reference)
|
||||||
|
|
||||||
# Get orientation of drone in euler angles
|
# Get orientation of drone in euler angles to determine yaw offset
|
||||||
drone_Eul = self.euler_array(drone_P.link_state.pose)
|
drone_Eul = self.euler_array(drone_P.link_state.pose.orientation)
|
||||||
|
|
||||||
# Check if payload is part of simulation
|
# Check if payload is part of simulation
|
||||||
if not drone_P.success:
|
if not drone_P.success:
|
||||||
self.status.drone_id = 'spiri::base'
|
self.status.drone_id = 'spiri::base'
|
||||||
|
@ -138,6 +140,9 @@ class Main:
|
||||||
|
|
||||||
if not self.has_run == 1:
|
if not self.has_run == 1:
|
||||||
if self.pload == True:
|
if self.pload == True:
|
||||||
|
# Determine yaw offset
|
||||||
|
self.yaw_offset = drone_Eul[2]
|
||||||
|
|
||||||
# Get tether length based off initial displacement
|
# Get tether length based off initial displacement
|
||||||
self.tetherL = math.sqrt((drone_P.link_state.pose.position.x -
|
self.tetherL = math.sqrt((drone_P.link_state.pose.position.x -
|
||||||
pload_P.link_state.pose.position.x)**2 +
|
pload_P.link_state.pose.position.x)**2 +
|
||||||
|
@ -158,6 +163,19 @@ class Main:
|
||||||
drone_Py = drone_P.link_state.pose.position.y
|
drone_Py = drone_P.link_state.pose.position.y
|
||||||
drone_Pz = drone_P.link_state.pose.position.z
|
drone_Pz = drone_P.link_state.pose.position.z
|
||||||
|
|
||||||
|
# Get drone orientation
|
||||||
|
drone_q = [drone_P.link_state.pose.orientation.x,drone_P.link_state.pose.orientation.y,
|
||||||
|
drone_P.link_state.pose.orientation.z,drone_P.link_state.pose.orientation.w]
|
||||||
|
|
||||||
|
# offset orientation by yaw offset
|
||||||
|
q_offset = quaternion_from_euler(0,0,-self.yaw_offset)
|
||||||
|
#drone_q = quaternion_multiply(drone_q,q_offset)
|
||||||
|
|
||||||
|
drone_P.link_state.pose.orientation.x = drone_q[0]
|
||||||
|
drone_P.link_state.pose.orientation.y = drone_q[1]
|
||||||
|
drone_P.link_state.pose.orientation.z = drone_q[2]
|
||||||
|
drone_P.link_state.pose.orientation.w = drone_q[3]
|
||||||
|
|
||||||
if self.pload == True: # If there is payload, determine the variables
|
if self.pload == True: # If there is payload, determine the variables
|
||||||
# Pload
|
# Pload
|
||||||
pload_Px = pload_P.link_state.pose.position.x
|
pload_Px = pload_P.link_state.pose.position.x
|
||||||
|
@ -195,7 +213,7 @@ class Main:
|
||||||
# Print and save results
|
# Print and save results
|
||||||
print "\n"
|
print "\n"
|
||||||
rospy.loginfo("")
|
rospy.loginfo("")
|
||||||
print"Roll: "+str(round(drone_Eul[0],2)),"\nPitch: "+str(round(drone_Eul[1],2)),"\nYaw: "+str(round(drone_Eul[2],2))
|
print"Roll: "+str(round(drone_Eul[0],2)),"\nPitch: "+str(round(drone_Eul[1],2)),"\nYaw: "+str(round(drone_Eul[2],4))
|
||||||
print "drone pos.x: " + str(round(drone_Px,2))
|
print "drone pos.x: " + str(round(drone_Px,2))
|
||||||
print "drone pos.y: " + str(round(drone_Py,2))
|
print "drone pos.y: " + str(round(drone_Py,2))
|
||||||
print "drone pos.z: " + str(round(drone_Pz,2))
|
print "drone pos.z: " + str(round(drone_Pz,2))
|
||||||
|
|
|
@ -9,7 +9,7 @@ import time
|
||||||
import math
|
import math
|
||||||
from tf.transformations import *
|
from tf.transformations import *
|
||||||
from oscillation_ctrl.msg import tethered_status
|
from oscillation_ctrl.msg import tethered_status
|
||||||
from geometry_msgs.msg import PoseStamped
|
from geometry_msgs.msg import PoseStamped, Point
|
||||||
from std_msgs.msg import Bool
|
from std_msgs.msg import Bool
|
||||||
|
|
||||||
class Main:
|
class Main:
|
||||||
|
@ -19,8 +19,6 @@ class Main:
|
||||||
# rate(s)
|
# rate(s)
|
||||||
rate = 40 # rate for the publisher method, specified in Hz -- 20 Hz
|
rate = 40 # rate for the publisher method, specified in Hz -- 20 Hz
|
||||||
|
|
||||||
self.dt = 1.0/rate
|
|
||||||
|
|
||||||
# Variables needed for testing start
|
# Variables needed for testing start
|
||||||
self.tstart = rospy.get_time() # Keep track of the start time
|
self.tstart = rospy.get_time() # Keep track of the start time
|
||||||
while self.tstart == 0.0: # Need to make sure get_rostime works
|
while self.tstart == 0.0: # Need to make sure get_rostime works
|
||||||
|
@ -41,19 +39,10 @@ class Main:
|
||||||
### -*-*-*- END -*-*-*- ###
|
### -*-*-*- END -*-*-*- ###
|
||||||
|
|
||||||
# initialize variables
|
# initialize variables
|
||||||
#self.buff_pose1 = PoseStamped()
|
|
||||||
self.drone_pose = PoseStamped()
|
self.drone_pose = PoseStamped()
|
||||||
self.buff_pose = PoseStamped()
|
self.buff_pose = PoseStamped()
|
||||||
|
|
||||||
# Debugging
|
self.eul = [0.0,0.0,0.0]
|
||||||
# self.buff_pose.pose.position.y = 0
|
|
||||||
# self.buff_pose.pose.position.x = 0
|
|
||||||
# self.buff_pose.pose.position.z = 0
|
|
||||||
# self.buff_pose.pose.orientation.y = 0
|
|
||||||
# self.buff_pose.pose.orientation.x = 0
|
|
||||||
# self.buff_pose.pose.orientation.z = 0
|
|
||||||
# self.buff_pose.pose.orientation.w = 1
|
|
||||||
# self.buff_pose.header.frame_id = 'map'
|
|
||||||
|
|
||||||
# Max dot values to prevent 'blowup'
|
# Max dot values to prevent 'blowup'
|
||||||
self.phidot_max = 3.0
|
self.phidot_max = 3.0
|
||||||
|
@ -71,12 +60,6 @@ class Main:
|
||||||
|
|
||||||
|
|
||||||
# publisher(s)
|
# publisher(s)
|
||||||
#self.publisher = rospy.Publisher('/status/twoBody_status', tethered_status, queue_size=1)
|
|
||||||
#self.pub_wd = rospy.Publisher('/status/path_follow', Bool, queue_size=1)
|
|
||||||
|
|
||||||
#self.pub_timer = rospy.Timer(rospy.Duration(1.0/rate), self.link_state)
|
|
||||||
#self.path_timer = rospy.Timer(rospy.Duration(40.0/rate), self.path_follow)
|
|
||||||
|
|
||||||
### Since there is no tether, we can publish directly to mavros
|
### 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.pose_pub = rospy.Publisher('/mavros/vision_pose/pose', PoseStamped, queue_size=1)
|
||||||
|
|
||||||
|
@ -104,18 +87,17 @@ class Main:
|
||||||
output = value
|
output = value
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def euler_array(self,pose):
|
def euler_array(self):
|
||||||
"""
|
"""
|
||||||
Takes in pose msg object and outputs array of euler angs:
|
Takes in pose msg object and outputs array of euler angs:
|
||||||
q[0] = Roll
|
eul[0] = Roll
|
||||||
q[1] = Pitch
|
eul[1] = Pitch
|
||||||
q[2] = Yaw
|
eul[2] = Yaw
|
||||||
"""
|
"""
|
||||||
q = euler_from_quaternion([pose.orientation.x,
|
self.eul = euler_from_quaternion([self.drone_pose.pose.orientation.x,
|
||||||
pose.orientation.y,
|
self.drone_pose.pose.orientation.y,
|
||||||
pose.orientation.z,
|
self.drone_pose.pose.orientation.z,
|
||||||
pose.orientation.w])
|
self.drone_pose.pose.orientation.w])
|
||||||
return q
|
|
||||||
|
|
||||||
def FRD_Transform(self):
|
def FRD_Transform(self):
|
||||||
'''
|
'''
|
||||||
|
@ -123,7 +105,20 @@ class Main:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
self.drone_pose = self.buff_pose
|
self.drone_pose = self.buff_pose
|
||||||
self.drone_pose.header.frame_id = "map"
|
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.x = self.buff_pose.pose.position.y
|
||||||
# self.drone_pose.pose.position.y = self.buff_pose.pose.position.x
|
# self.drone_pose.pose.position.y = self.buff_pose.pose.position.x
|
||||||
# self.drone_pose.pose.position.z = -self.buff_pose.pose.position.z
|
# self.drone_pose.pose.position.z = -self.buff_pose.pose.position.z
|
||||||
|
@ -157,6 +152,9 @@ class Main:
|
||||||
print "drone pos.x: " + str(round(self.drone_pose.pose.position.x,2))
|
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.y: " + str(round(self.drone_pose.pose.position.y,2))
|
||||||
print "drone pos.z: " + str(round(self.drone_pose.pose.position.z,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__":
|
if __name__=="__main__":
|
||||||
|
|
|
@ -308,9 +308,6 @@ class Main:
|
||||||
|
|
||||||
# Attitude control
|
# Attitude control
|
||||||
self.quaternion.header.stamp = rospy.Time.now()
|
self.quaternion.header.stamp = rospy.Time.now()
|
||||||
# self.quaternion.pose.position.x = 0
|
|
||||||
# self.quaternion.pose.position.y = 0
|
|
||||||
# self.quaternion.pose.position.z = 5.0
|
|
||||||
self.quaternion.pose.orientation.x = q[0]
|
self.quaternion.pose.orientation.x = q[0]
|
||||||
self.quaternion.pose.orientation.y = q[1]
|
self.quaternion.pose.orientation.y = q[1]
|
||||||
self.quaternion.pose.orientation.z = q[2]
|
self.quaternion.pose.orientation.z = q[2]
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
* @file offb_node.cpp
|
* @file offb_node.cpp
|
||||||
* @brief Offboard control example node, written with MAVROS version 0.19.x, PX4 Pro Flight
|
* @brief Offboard control example node, written with MAVROS version 0.19.x, PX4 Pro Flight
|
||||||
* Stack and tested in Gazebo SITL
|
* Stack and tested in Gazebo SITL
|
||||||
* Cesar: Now used for path following on topic \path
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ros/ros.h>
|
#include <ros/ros.h>
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
#include <ros/ros.h>
|
#include <ros/ros.h>
|
||||||
#include <sensor_msgs/NavSatFix.h>
|
#include <sensor_msgs/NavSatFix.h>
|
||||||
#include <offboard_ex/RefSignal.h>
|
#include <oscillation_ctrl/RefSignal.h>
|
||||||
#include <offboard_ex/EulerAngles.h>
|
#include <oscillation_ctrl/EulerAngles.h>
|
||||||
|
#include <oscillation_ctrl/WaypointTrack.h>
|
||||||
#include <geometry_msgs/PoseStamped.h>
|
#include <geometry_msgs/PoseStamped.h>
|
||||||
#include <geometry_msgs/Quaternion.h>
|
#include <geometry_msgs/Quaternion.h>
|
||||||
#include <geometry_msgs/Vector3.h>
|
#include <geometry_msgs/Vector3.h>
|
||||||
|
@ -31,7 +32,7 @@ geometry_msgs::PoseStamped desPose;
|
||||||
tf2::Quaternion q_cmd /*What I send*/, q_Jae; // What should be sent;
|
tf2::Quaternion q_cmd /*What I send*/, q_Jae; // What should be sent;
|
||||||
double rol_K, pch_K, yaw_K, rol_J, pch_J, yaw_J; // Same logic, K = cmd
|
double rol_K, pch_K, yaw_K, rol_J, pch_J, yaw_J; // Same logic, K = cmd
|
||||||
geometry_msgs::Vector3 K_ang, J_ang; // Needed to populate EulerAngle msg
|
geometry_msgs::Vector3 K_ang, J_ang; // Needed to populate EulerAngle msg
|
||||||
offboard_ex::EulerAngles eulAng;
|
oscillation_ctrl::EulerAngles eulAng;
|
||||||
|
|
||||||
mavros_msgs::AttitudeTarget thrust;
|
mavros_msgs::AttitudeTarget thrust;
|
||||||
|
|
||||||
|
@ -42,12 +43,9 @@ void state_cb(const mavros_msgs::State::ConstPtr& msg){
|
||||||
}
|
}
|
||||||
|
|
||||||
geometry_msgs::Quaternion q_des;
|
geometry_msgs::Quaternion q_des;
|
||||||
double alt_des; // Check desired height
|
|
||||||
|
|
||||||
// Cb to determine desired pose *Only needed for orientation
|
// Cb to determine desired pose *Only needed for orientation
|
||||||
void q_cb(const geometry_msgs::PoseStamped::ConstPtr& msg){
|
void q_cb(const geometry_msgs::PoseStamped::ConstPtr& msg){
|
||||||
desPose = *msg;
|
desPose = *msg;
|
||||||
alt_des = desPose.pose.position.z;
|
|
||||||
q_des = desPose.pose.orientation;
|
q_des = desPose.pose.orientation;
|
||||||
tf2::convert(q_des,q_cmd); // Convert msg type to tf2::quaternion type
|
tf2::convert(q_des,q_cmd); // Convert msg type to tf2::quaternion type
|
||||||
}
|
}
|
||||||
|
@ -83,7 +81,6 @@ void thrust_cb(const mavros_msgs::AttitudeTarget msg){
|
||||||
tf2::convert(thrust.orientation,q_Jae); // Convert from msg to quat
|
tf2::convert(thrust.orientation,q_Jae); // Convert from msg to quat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
ros::init(argc, argv, "path_follow");
|
ros::init(argc, argv, "path_follow");
|
||||||
|
@ -116,7 +113,7 @@ int main(int argc, char **argv)
|
||||||
("mavros/setpoint_raw/attitude",10);
|
("mavros/setpoint_raw/attitude",10);
|
||||||
|
|
||||||
// Publish attitude cmds in euler angles
|
// Publish attitude cmds in euler angles
|
||||||
ros::Publisher euler_pub = nh.advertise<offboard_ex::EulerAngles>
|
ros::Publisher euler_pub = nh.advertise<oscillation_ctrl::EulerAngles>
|
||||||
("command/euler_angles",10);
|
("command/euler_angles",10);
|
||||||
|
|
||||||
// Service Clients
|
// Service Clients
|
||||||
|
@ -126,6 +123,8 @@ int main(int argc, char **argv)
|
||||||
("mavros/set_mode");
|
("mavros/set_mode");
|
||||||
ros::ServiceClient takeoff_cl = nh.serviceClient<mavros_msgs::CommandTOL>
|
ros::ServiceClient takeoff_cl = nh.serviceClient<mavros_msgs::CommandTOL>
|
||||||
("mavros/cmd/takeoff");
|
("mavros/cmd/takeoff");
|
||||||
|
ros::ServiceClient waypoint_cl = nh.serviceClient<oscillation_ctrl::WaypointTrack>
|
||||||
|
("status/waypoint_tracker");
|
||||||
|
|
||||||
//the setpoint publishing rate MUST be faster than 2Hz... PX4 timeout = 500 ms
|
//the setpoint publishing rate MUST be faster than 2Hz... PX4 timeout = 500 ms
|
||||||
ros::Rate rate(20.0);
|
ros::Rate rate(20.0);
|
||||||
|
@ -140,18 +139,24 @@ int main(int argc, char **argv)
|
||||||
/*********** Initiate variables ************************/
|
/*********** Initiate variables ************************/
|
||||||
// Needed for attitude command
|
// Needed for attitude command
|
||||||
mavros_msgs::AttitudeTarget attitude;
|
mavros_msgs::AttitudeTarget attitude;
|
||||||
|
|
||||||
attitude.header.frame_id = "map"; // NED Ref Frame(?) #TODO
|
attitude.header.frame_id = "map"; // NED Ref Frame(?) #TODO
|
||||||
attitude.type_mask = 1|2|4; // Ignore body rates
|
attitude.type_mask = 1|2|4; // Ignore body rates
|
||||||
|
|
||||||
// Retrieve parameters from Ctrl_param.yaml file
|
// Retrieve desired waypoints
|
||||||
/*std::vector<double> waypoints;
|
oscillation_ctrl::WaypointTrack wpoint_srv;
|
||||||
nh.getParam("sim/waypoints",waypoints);
|
wpoint_srv.request.query = false;
|
||||||
|
if (waypoint_cl.call(wpoint_srv))
|
||||||
// Need to send pose commands until throttle has been established
|
{
|
||||||
buff_pose.pose.position.x = waypoints(1);
|
ROS_INFO("Waypoints received");
|
||||||
buff_pose.pose.position.y = waypoints(2);
|
}
|
||||||
buff_pose.pose.position.z = waypoints(3);*/
|
|
||||||
|
// populate desired waypoints - this is only for original hover as
|
||||||
|
// a change of waypoints is handled by ref_signal.py
|
||||||
|
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;
|
||||||
|
double alt_des = buff_pose.pose.position.z; // Desired height
|
||||||
|
|
||||||
// Desired mode is offboard
|
// Desired mode is offboard
|
||||||
mavros_msgs::SetMode offb_set_mode;
|
mavros_msgs::SetMode offb_set_mode;
|
||||||
|
|
|
@ -8,22 +8,17 @@ import numpy as np
|
||||||
import time
|
import time
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
from pymavlink import mavutil
|
||||||
from scipy import signal
|
from scipy import signal
|
||||||
from scipy.integrate import odeint
|
from scipy.integrate import odeint
|
||||||
|
|
||||||
from oscillation_ctrl.msg import tethered_status, RefSignal
|
from oscillation_ctrl.msg import tethered_status, RefSignal
|
||||||
|
from oscillation_ctrl.srv import WaypointTrack, WaypointTrackRequest
|
||||||
from controller_msgs.msg import FlatTarget
|
from controller_msgs.msg import FlatTarget
|
||||||
|
from geometry_msgs.msg import Pose, Vector3, PoseStamped, Point, TwistStamped
|
||||||
from geometry_msgs.msg import Pose, Vector3, PoseStamped, Point
|
|
||||||
|
|
||||||
from geometry_msgs.msg import TwistStamped
|
|
||||||
from sensor_msgs.msg import Imu
|
from sensor_msgs.msg import Imu
|
||||||
|
|
||||||
from mavros_msgs.msg import State
|
from mavros_msgs.msg import State
|
||||||
|
|
||||||
from pymavlink import mavutil
|
|
||||||
|
|
||||||
class Main:
|
class Main:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -35,6 +30,7 @@ class Main:
|
||||||
self.tstart = rospy.get_time() # Keep track of the start time
|
self.tstart = rospy.get_time() # Keep track of the start time
|
||||||
while self.tstart == 0.0: # Need to make sure get_rostime works
|
while self.tstart == 0.0: # Need to make sure get_rostime works
|
||||||
self.tstart = rospy.get_time()
|
self.tstart = rospy.get_time()
|
||||||
|
rospy.loginfo(self.tstart)
|
||||||
|
|
||||||
self.dt = 1.0/rate
|
self.dt = 1.0/rate
|
||||||
# self.dt = 0.5
|
# self.dt = 0.5
|
||||||
|
@ -71,6 +67,33 @@ class Main:
|
||||||
if rospy.has_param('sim/tether_length'):
|
if rospy.has_param('sim/tether_length'):
|
||||||
self.tetherL = rospy.get_param('sim/tether_length') # Tether length
|
self.tetherL = rospy.get_param('sim/tether_length') # Tether length
|
||||||
self.param_exists = True
|
self.param_exists = True
|
||||||
|
elif rospy.get_time() - self.tstart >= 3.0:
|
||||||
|
self.tetherL = 0.0
|
||||||
|
break
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------------#
|
||||||
|
# SUBSCRIBERS #
|
||||||
|
# --------------------------------------------------------------------------------#
|
||||||
|
# Topic, msg type, and class callback method
|
||||||
|
rospy.Subscriber('/status/twoBody_status', tethered_status, self.linkState_cb)
|
||||||
|
rospy.Subscriber('/mavros/local_position/velocity_body', TwistStamped, self.droneVel_cb)
|
||||||
|
rospy.Subscriber('/mavros/imu/data', Imu, self.droneAcc_cb)
|
||||||
|
rospy.Subscriber('/mavros/state', State, self.state_cb)
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------------#
|
||||||
|
# PUBLISHERS
|
||||||
|
# --------------------------------------------------------------------------------#
|
||||||
|
# Publish desired path to compute attitudes
|
||||||
|
self.pub_path = rospy.Publisher('/reference/path',FlatTarget,queue_size = 10)
|
||||||
|
# Needed for geometric controller to compute thrust
|
||||||
|
self.pub_ref = rospy.Publisher('/reference/flatsetpoint',FlatTarget,queue_size = 10)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------------#
|
||||||
|
# FEEDBACK AND INPUT SHAPING
|
||||||
|
# --------------------------------------------------------------------------------#
|
||||||
|
|
||||||
# Smooth path variables
|
# Smooth path variables
|
||||||
self.EPS_F = np.zeros(9) # Final Epsilon/ signal
|
self.EPS_F = np.zeros(9) # Final Epsilon/ signal
|
||||||
|
@ -79,7 +102,12 @@ class Main:
|
||||||
# Constants for smooth path generation
|
# Constants for smooth path generation
|
||||||
self.w_tune = 3.13 # 3.13 works well? #########################################################################
|
self.w_tune = 3.13 # 3.13 works well? #########################################################################
|
||||||
self.epsilon = 0.7 # Damping ratio
|
self.epsilon = 0.7 # Damping ratio
|
||||||
self.wn = math.sqrt(9.81/self.tetherL)
|
|
||||||
|
# need exception if we do not have tether:
|
||||||
|
if self.tetherL == 0.0:
|
||||||
|
self.wn = self.w_tune
|
||||||
|
else:
|
||||||
|
self.wn = math.sqrt(9.81/self.tetherL)
|
||||||
self.wd = self.wn*math.sqrt(1 - self.epsilon**2)
|
self.wd = self.wn*math.sqrt(1 - self.epsilon**2)
|
||||||
self.k4 = 4*self.epsilon*self.w_tune
|
self.k4 = 4*self.epsilon*self.w_tune
|
||||||
self.k3 = ((2 + 4*self.epsilon**2)*self.w_tune**2)/self.k4
|
self.k3 = ((2 + 4*self.epsilon**2)*self.w_tune**2)/self.k4
|
||||||
|
@ -100,9 +128,9 @@ class Main:
|
||||||
#elif rospy.get_time() - self.tstart >= 3.0:
|
#elif rospy.get_time() - self.tstart >= 3.0:
|
||||||
# self.xd = np.array([[0],[0],[5.0]]) # make our own if there are no waypoints
|
# self.xd = np.array([[0],[0],[5.0]]) # make our own if there are no waypoints
|
||||||
|
|
||||||
self.xd = Point()
|
#self.xd = Point()
|
||||||
self.get_xd = rospy.ServiceProxy('status/waypoint_tracker',WaypointTrack)
|
self.get_xd = rospy.ServiceProxy('/status/waypoint_tracker',WaypointTrack)
|
||||||
|
self.empty_point = Point() # Needed to query waypoint_server
|
||||||
|
|
||||||
self.des_waypoints = True # True = changing waypoints
|
self.des_waypoints = True # True = changing waypoints
|
||||||
|
|
||||||
|
@ -111,10 +139,6 @@ class Main:
|
||||||
self.y0 = [0, 0, 0, 0]
|
self.y0 = [0, 0, 0, 0]
|
||||||
self.z0 = [0, 0, 0, 0]
|
self.z0 = [0, 0, 0, 0]
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------#
|
|
||||||
# FEEDBACK AND INPUT SHAPING
|
|
||||||
# --------------------------------------------------------------------------------#
|
|
||||||
|
|
||||||
# Constants for feedback
|
# Constants for feedback
|
||||||
self.Gd = 0.325
|
self.Gd = 0.325
|
||||||
self.td = 2*self.Gd*math.pi/self.wd
|
self.td = 2*self.Gd*math.pi/self.wd
|
||||||
|
@ -148,30 +172,6 @@ class Main:
|
||||||
self.sk = len(self.SF_delay_x[0]) # from Klausen 2017
|
self.sk = len(self.SF_delay_x[0]) # from Klausen 2017
|
||||||
self.ak = np.zeros(len(self.SF_delay_x[0]))
|
self.ak = np.zeros(len(self.SF_delay_x[0]))
|
||||||
self.s_gain = 0.0 # Gain found from sigmoid
|
self.s_gain = 0.0 # Gain found from sigmoid
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------#
|
|
||||||
# SUBSCRIBERS #
|
|
||||||
# --------------------------------------------------------------------------------#
|
|
||||||
# Topic, msg type, and class callback method
|
|
||||||
rospy.Subscriber('/status/twoBody_status', tethered_status, self.linkState_cb)
|
|
||||||
rospy.Subscriber('/mavros/local_position/velocity_body', TwistStamped, self.droneVel_cb)
|
|
||||||
rospy.Subscriber('/mavros/imu/data', Imu, self.droneAcc_cb)
|
|
||||||
rospy.Subscriber('/mavros/state', State, self.state_cb)
|
|
||||||
#rospy.Subscriber('/reference/waypoints',Position, self.waypoints_cb) ### Change to position
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------#
|
|
||||||
# PUBLISHERS
|
|
||||||
# --------------------------------------------------------------------------------#
|
|
||||||
# Publish desired path to compute attitudes
|
|
||||||
self.pub_path = rospy.Publisher('/reference/path',FlatTarget,queue_size = 10)
|
|
||||||
# Needed for geometric controller to compute thrust
|
|
||||||
self.pub_ref = rospy.Publisher('/reference/flatsetpoint',FlatTarget,queue_size = 10)
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
# ------------------------------------ _init_ ends ------------------------------ #
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------#
|
# --------------------------------------------------------------------------------#
|
||||||
# CALLBACK FUNCTIONS
|
# CALLBACK FUNCTIONS
|
||||||
# --------------------------------------------------------------------------------#
|
# --------------------------------------------------------------------------------#
|
||||||
|
@ -230,13 +230,18 @@ class Main:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def waypoints_srv_cb(self):
|
def waypoints_srv_cb(self):
|
||||||
rospy.wait_for_service('status/waypoint_tracker')
|
rospy.wait_for_service('/status/waypoint_tracker')
|
||||||
try:
|
try:
|
||||||
self.xd = self.get_xd(True)
|
resp = self.get_xd(False,self.empty_point)
|
||||||
# if self.des_waypoints == True:
|
self.xd = resp.xd
|
||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
#################################################################
|
||||||
|
#TODO Will need to add a function that gets a message from #
|
||||||
|
# a node which lets refsignal_gen.py know there has been a #
|
||||||
|
# change in xd and therefore runs waypoints_srv_cb again #
|
||||||
|
#################################################################
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------#
|
# --------------------------------------------------------------------------------#
|
||||||
# ALGORITHM
|
# ALGORITHM
|
||||||
|
@ -322,9 +327,9 @@ class Main:
|
||||||
else:
|
else:
|
||||||
print('No delay')
|
print('No delay')
|
||||||
|
|
||||||
# Convolution and input shape filter, and feedback
|
# Convolution of shape filter and trajectory, and feedback
|
||||||
def convo(self):
|
def convo(self):
|
||||||
|
self.waypoints_srv_cb()
|
||||||
# needed for delay function
|
# needed for delay function
|
||||||
# 1 = determine shapefilter array
|
# 1 = determine shapefilter array
|
||||||
# 2 = determine theta/phi_fb
|
# 2 = determine theta/phi_fb
|
||||||
|
@ -332,9 +337,9 @@ class Main:
|
||||||
feedBack = 2
|
feedBack = 2
|
||||||
|
|
||||||
# SOLVE ODE (get ref pos, vel, accel)
|
# SOLVE ODE (get ref pos, vel, accel)
|
||||||
self.x = odeint(self.statespace,self.x0,self.t,args=(self.xd[0],))
|
self.x = odeint(self.statespace,self.x0,self.t,args=(self.xd.x,))
|
||||||
self.y = odeint(self.statespace,self.y0,self.t,args=(self.xd[1],))
|
self.y = odeint(self.statespace,self.y0,self.t,args=(self.xd.y,))
|
||||||
self.z = odeint(self.statespace,self.z0,self.t,args=(self.xd[2],))
|
self.z = odeint(self.statespace,self.z0,self.t,args=(self.xd.z,))
|
||||||
|
|
||||||
for i in range(1,len(self.y0)):
|
for i in range(1,len(self.y0)):
|
||||||
self.x[:,i] = np.clip(self.x[:,i], a_min = -self.max[i], a_max = self.max[i])
|
self.x[:,i] = np.clip(self.x[:,i], a_min = -self.max[i], a_max = self.max[i])
|
||||||
|
@ -343,7 +348,7 @@ class Main:
|
||||||
|
|
||||||
for j in range(3): # 3 is due to pos, vel, acc. NOT due x, y, z
|
for j in range(3): # 3 is due to pos, vel, acc. NOT due x, y, z
|
||||||
|
|
||||||
self.delay(j,shapeFil) # Determine the delay array
|
self.delay(j,shapeFil) # Determine the delay (shapefilter) array
|
||||||
|
|
||||||
if self.SF_idx < len(self.SF_delay_x[0]):
|
if self.SF_idx < len(self.SF_delay_x[0]):
|
||||||
self.EPS_I[3*j] = self.x[1,j]
|
self.EPS_I[3*j] = self.x[1,j]
|
||||||
|
@ -363,9 +368,21 @@ class Main:
|
||||||
# Populate EPS_F buffer with desired change based on feedback
|
# Populate EPS_F buffer with desired change based on feedback
|
||||||
self.EPS_F[i] = self.EPS_I[i] + EPS_D[i] #+ EPS_D[i]
|
self.EPS_F[i] = self.EPS_I[i] + EPS_D[i] #+ EPS_D[i]
|
||||||
|
|
||||||
# self.x0 = [self.dr_pos.position.x, self.dr_vel.x, self.dr_acc.x, self.x[1,3]]
|
# Populate msg with epsilon_final
|
||||||
# self.y0 = [self.dr_pos.position.y, self.dr_vel.y, self.dr_acc.y, self.y[1,3]]
|
self.ref_sig.header.stamp = rospy.Time.now()
|
||||||
# self.z0 = [self.dr_pos.position.z, self.dr_vel.z, self.dr_acc.z, self.z[1,3]]
|
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] + 0.5
|
||||||
|
|
||||||
|
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]
|
||||||
|
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.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.y0 = [self.dr_pos.position.y, self.y[1,1], self.y[1,2], self.y[1,3]]
|
||||||
|
@ -389,37 +406,31 @@ class Main:
|
||||||
|
|
||||||
return EPS_D
|
return EPS_D
|
||||||
|
|
||||||
def publisher(self,pub_tim):
|
def screen_output(self):
|
||||||
|
|
||||||
# Determine final ref signal
|
|
||||||
self.convo()
|
|
||||||
|
|
||||||
# Populate msg with epsilon_final
|
|
||||||
self.ref_sig.position.x = self.EPS_F[0]
|
|
||||||
self.ref_sig.position.y = self.EPS_F[1]
|
|
||||||
|
|
||||||
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]
|
|
||||||
self.ref_sig.acceleration.z = self.EPS_F[8]
|
|
||||||
|
|
||||||
# Need typemask = 2 to use correct attitude controller - Jaeyoung Lin
|
|
||||||
self.ref_sig.type_mask = 2
|
|
||||||
|
|
||||||
# Publish command
|
|
||||||
self.ref_sig.header.stamp = rospy.Time.now()
|
|
||||||
self.pub_path.publish(self.ref_sig)
|
|
||||||
self.pub_ref.publish(self.ref_sig)
|
|
||||||
|
|
||||||
# Feedback to user
|
# Feedback to user
|
||||||
rospy.loginfo(' Var | x | y | z ')
|
rospy.loginfo(' Var | x | y | z ')
|
||||||
rospy.loginfo('Pos: %.2f %.2f %.2f',self.EPS_F[0],self.EPS_F[1],self.EPS_F[2])
|
rospy.loginfo('Pos: %.2f %.2f %.2f',self.EPS_F[0],self.EPS_F[1],self.EPS_F[2])
|
||||||
rospy.loginfo('Vel: %.2f %.2f %.2f',self.EPS_F[3],self.EPS_F[4],self.EPS_F[5])
|
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('Acc: %.2f %.2f %.2f',self.EPS_F[6],self.EPS_F[7],self.EPS_F[8])
|
||||||
rospy.loginfo('_______________________')
|
rospy.loginfo('_______________________')
|
||||||
|
|
||||||
|
def publisher(self,pub_tim):
|
||||||
|
|
||||||
|
# Determine final ref signal
|
||||||
|
self.convo()
|
||||||
|
|
||||||
|
# Publish reference signal
|
||||||
|
self.pub_path.publish(self.ref_sig)
|
||||||
|
self.pub_ref.publish(self.ref_sig)
|
||||||
|
|
||||||
|
# Give user feedback on published message:
|
||||||
|
rospy.loginfo(' Var | x | y | z ')
|
||||||
|
rospy.loginfo('Pos: %.2f %.2f %.2f',self.EPS_F[0],self.EPS_F[1],self.EPS_F[2])
|
||||||
|
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('_______________________')
|
||||||
|
|
||||||
|
|
||||||
if __name__=="__main__":
|
if __name__=="__main__":
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
### Script to generate set points which form a square with 2m side lengths
|
### Script to generate set points which form a square with 2m side lengths
|
||||||
import rospy, tf
|
import rospy, tf
|
||||||
import time
|
import time
|
||||||
from geometry_msgs.msg import PoseStamped
|
from geometry_msgs.msg import Point
|
||||||
from std_msgs.msg import Bool
|
from std_msgs.msg import Bool
|
||||||
|
|
||||||
class Main:
|
class Main:
|
||||||
|
@ -13,11 +13,11 @@ class Main:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
# variable(s)
|
# variable(s)
|
||||||
self.Point = PoseStamped()
|
self.Point = Point()
|
||||||
# Init x, y, & z coordinates
|
# Init x, y, & z coordinates
|
||||||
self.Point.pose.position.x = 0
|
self.Point.x = 0
|
||||||
self.Point.pose.position.y = 0
|
self.Point.y = 0
|
||||||
self.Point.pose.position.z = 3.5
|
self.Point.z = 3.5
|
||||||
|
|
||||||
self.xarray = [1,2,2,2,1,0,0]
|
self.xarray = [1,2,2,2,1,0,0]
|
||||||
self.yarray = [0,0,1,2,2,2,1]
|
self.yarray = [0,0,1,2,2,2,1]
|
||||||
|
@ -30,7 +30,7 @@ class Main:
|
||||||
rospy.Subscriber('/status/path_follow',Bool, self.wait_cb)
|
rospy.Subscriber('/status/path_follow',Bool, self.wait_cb)
|
||||||
|
|
||||||
# publisher(s), with specified topic, message type, and queue_size
|
# publisher(s), with specified topic, message type, and queue_size
|
||||||
self.pub_square = rospy.Publisher('/reference/waypoints', PoseStamped, queue_size = 5)
|
self.pub_square = rospy.Publisher('/reference/waypoints', Point, queue_size = 5)
|
||||||
|
|
||||||
# rate(s)
|
# rate(s)
|
||||||
pub_rate = 1 # rate for the publisher method, specified in Hz
|
pub_rate = 1 # rate for the publisher method, specified in Hz
|
||||||
|
@ -49,28 +49,28 @@ class Main:
|
||||||
else:
|
else:
|
||||||
# Check if i is too large. loop back to first point
|
# Check if i is too large. loop back to first point
|
||||||
if self.i >= len(self.xarray):
|
if self.i >= len(self.xarray):
|
||||||
self.Point.pose.position.x = 0
|
self.Point.x = 0
|
||||||
self.Point.pose.position.y = 0
|
self.Point.y = 0
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.Point.pose.position.x = self.xarray[self.i]
|
self.Point.x = self.xarray[self.i]
|
||||||
self.Point.pose.position.y = self.yarray[self.i]
|
self.Point.y = self.yarray[self.i]
|
||||||
|
|
||||||
rospy.loginfo("Sending [Point x] %d [Point y] %d",
|
rospy.loginfo("Sending [Point x] %d [Point y] %d",
|
||||||
self.Point.pose.position.x, self.Point.pose.position.y)
|
self.Point.x, self.Point.y)
|
||||||
|
|
||||||
# Published desired msgs
|
# Published desired msgs
|
||||||
self.Point.header.stamp = rospy.Time.now()
|
# self.Point.header.stamp = rospy.Time.now()
|
||||||
self.pub_square.publish(self.Point)
|
self.pub_square.publish(self.Point)
|
||||||
self.j += 1
|
self.j += 1
|
||||||
self.i = self.j // self.buffer
|
self.i = self.j // self.buffer
|
||||||
|
|
||||||
# self.Point.header.stamp = rospy.Time.now()
|
# self.Point.header.stamp = rospy.Time.now()
|
||||||
# self.Point.pose.position.x = self.xarray[self.i]
|
# self.Point.x = self.xarray[self.i]
|
||||||
# self.Point.pose.position.y = self.yarray[self.i]
|
# self.Point.y = self.yarray[self.i]
|
||||||
|
|
||||||
# rospy.loginfo("Sending [Point x] %d [Point y] %d",
|
# rospy.loginfo("Sending [Point x] %d [Point y] %d",
|
||||||
# self.Point.pose.position.x, self.Point.pose.position.y)
|
# self.Point.x, self.Point.y)
|
||||||
|
|
||||||
# Published desired msgs
|
# Published desired msgs
|
||||||
# self.pub_square.publish(self.Point)
|
# self.pub_square.publish(self.Point)
|
||||||
|
|
10
src/step.py
10
src/step.py
|
@ -14,9 +14,9 @@ class Main:
|
||||||
# variable(s)
|
# variable(s)
|
||||||
self.Point = Point()
|
self.Point = Point()
|
||||||
# Init x, y, & z coordinates
|
# Init x, y, & z coordinates
|
||||||
self.Point.pose.position.x = 1
|
self.Point.x = 1
|
||||||
self.Point.pose.position.y = 0
|
self.Point.y = 0
|
||||||
self.Point.pose.position.z = 4.0
|
self.Point.z = 4.0
|
||||||
|
|
||||||
self.bool = False
|
self.bool = False
|
||||||
|
|
||||||
|
@ -41,13 +41,13 @@ class Main:
|
||||||
if self.bool == False:
|
if self.bool == False:
|
||||||
rospy.loginfo('Waiting...')
|
rospy.loginfo('Waiting...')
|
||||||
else:
|
else:
|
||||||
self.Point.header.stamp = rospy.Time.now()
|
#self.Point.header.stamp = rospy.Time.now()
|
||||||
|
|
||||||
# Published desired msgs
|
# Published desired msgs
|
||||||
self.pub_step.publish(self.Point)
|
self.pub_step.publish(self.Point)
|
||||||
|
|
||||||
rospy.loginfo("Sending [Point x] %d [Point y] %d",
|
rospy.loginfo("Sending [Point x] %d [Point y] %d",
|
||||||
self.Point.pose.position.x, self.Point.pose.position.y)
|
self.Point.x, self.Point.y)
|
||||||
|
|
||||||
if __name__=="__main__":
|
if __name__=="__main__":
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ class Main:
|
||||||
self.xd.x = 0.0
|
self.xd.x = 0.0
|
||||||
self.xd.y = 0.0
|
self.xd.y = 0.0
|
||||||
self.xd.z = 5.0
|
self.xd.z = 5.0
|
||||||
|
break
|
||||||
|
|
||||||
# service(s)
|
# service(s)
|
||||||
|
|
||||||
|
@ -47,7 +48,12 @@ class Main:
|
||||||
|
|
||||||
|
|
||||||
def waypoint_relay(self,req):
|
def waypoint_relay(self,req):
|
||||||
self.resp.xd = self.xd
|
#TODO Need to add check to make sure query is boolean
|
||||||
|
if req.query:
|
||||||
|
self.xd = req.xd
|
||||||
|
self.resp.xd = self.xd
|
||||||
|
else:
|
||||||
|
self.resp.xd = self.xd
|
||||||
return self.resp
|
return self.resp
|
||||||
|
|
||||||
# Change desired position if there is a change
|
# Change desired position if there is a change
|
||||||
|
@ -63,7 +69,9 @@ if __name__=="__main__":
|
||||||
rospy.init_node('waypoints_server',anonymous=False)
|
rospy.init_node('waypoints_server',anonymous=False)
|
||||||
try:
|
try:
|
||||||
obj = Main() # create class object
|
obj = Main() # create class object
|
||||||
s = rospy.Service('status/waypoint_tracker',WaypointTrack,obj.waypoint_relay)
|
s = rospy.Service('status/waypoint_tracker',WaypointTrack,obj.waypoint_relay)
|
||||||
|
rospy.loginfo_once('waypoints_server has started with:\nxd.x = %.1f\nxd.y = %.1f\nxd.z = %.1f', obj.xd.x, obj.xd.y, obj.xd.z)
|
||||||
|
|
||||||
rospy.spin() # loop until shutdown signal
|
rospy.spin() # loop until shutdown signal
|
||||||
|
|
||||||
except rospy.ROSInterruptException:
|
except rospy.ROSInterruptException:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
bool query # bool to request waypoints
|
bool query # bool to request or set waypoints
|
||||||
|
geometry_msgs/Point xd # waypoints
|
||||||
---
|
---
|
||||||
geometry_msgs/Point xd # waypoints
|
geometry_msgs/Point xd # waypoints
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue