réglages démo

This commit is contained in:
Hugo LEVY-FALK 2019-06-06 21:05:10 +02:00
parent 69cccc4615
commit 704168f2ca
23 changed files with 741 additions and 20 deletions

View file

@ -3,23 +3,31 @@
<arg name="output" default="output"/>
<arg name="measure" default="measure"/>
<arg name="reset" default="reset"/>
<node name="input" pkg="detect_targets" type="control_compute.py" args="input">
<arg name="param_P" default="simple_loop/linear_x/P.yaml" />
<arg name="param_I" default="simple_loop/linear_x/I.yaml" />
<arg name="param_D" default="simple_loop/linear_x/D.yaml" />
<arg name="param_input" default="params/simple_loop/linear_x/input.yaml" />
<node name="P_param" pkg="dynamic_reconfigure" type="dynparam" args="load P $(find detect_targets)/params/$(arg param_P)"/>
<node name="I_param" pkg="dynamic_reconfigure" type="dynparam" args="load I $(find detect_targets)/params/$(arg param_I)"/>
<node name="D_param" pkg="dynamic_reconfigure" type="dynparam" args="load D $(find detect_targets)/params/$(arg param_D)"/>
<node name="input_param" pkg="dynamic_reconfigure" type="dynparam" args="load input $(find detect_targets)/params/$(arg param_input)"/>
<node name="input" pkg="detect_targets" type="control_compute.py" args="input" output="screen">
<remap from="input" to="$(arg input)" />
<remap from="output" to="set_point"/>
<remap from="reset" to="$(arg reset)" />
</node>
<node name="diff" pkg="detect_targets" type="control_compute.py" args="differenciate">
<node name="diff" pkg="detect_targets" type="control_compute.py" args="differenciate" output="screen">
<remap from="input" to="set_point"/>
<remap from="output" to="epsilon"/>
<remap from="measure" to="$(arg measure)" />
<remap from="reset" to="$(arg reset)" />
</node>
<node name="P" pkg="detect_targets" type="control_compute.py" args="proportional">
<node name="P" pkg="detect_targets" type="control_compute.py" args="proportional" output="screen">
<remap from="input" to="epsilon"/>
<remap from="output" to="p_out"/>
<remap from="reset" to="$(arg reset)" />
</node>
<node name="I" pkg="detect_targets" type="control_compute.py" args="integral">
<node name="I" pkg="detect_targets" type="control_compute.py" args="integral" output="screen">
<remap from="input" to="epsilon"/>
<remap from="output" to="i_out"/>
<remap from="reset" to="$(arg reset)" />

94
launch/simple_loop.launch Normal file
View file

@ -0,0 +1,94 @@
<launch>
<node name="Ratex_param" pkg="dynamic_reconfigure" type="dynparam" args="load /ratex $(find detect_targets)/params/rate.yaml"/>
<node name="Ratey_param" pkg="dynamic_reconfigure" type="dynparam" args="load /ratey $(find detect_targets)/params/rate.yaml"/>
<node name="Ratez_param" pkg="dynamic_reconfigure" type="dynparam" args="load /ratez $(find detect_targets)/params/rate.yaml"/>
<node name="Rateangz_param" pkg="dynamic_reconfigure" type="dynparam" args="load /rate_ang_z $(find detect_targets)/params/rate.yaml"/>
<node name="safe_param" pkg="dynamic_reconfigure" type="dynparam" args="load /safe $(find detect_targets)/params/settings_safe.yaml"/>
<node name="targets_param" pkg="dynamic_reconfigure" type="dynparam" args="load /targets $(find detect_targets)/params/settings_targets.yaml"/>
<!-- <remap from="/reset" to="/bebop/reset"/> -->
<include file="$(find bebop_driver)/launch/bebop_node.launch" />
<node name="targets" pkg="detect_targets" type="target_publisher.py">
</node>
<node name="triangle" pkg="detect_targets" type="triangle.py" output="screen">
<remap from="component_centers" to="targets"/>
</node>
<node name="ratex" pkg="detect_targets" type="control_compute.py" args="rate" output="screen">
<remap from="input" to="linear_x" />
<remap from="output" to="rated_x" />
</node>
<include file="$(find detect_targets)/launch/control.launch" ns="controller_linear_x">
<arg name="reset" value="/reset_pid" />
<arg name="measure" value="/rated_x" />
<arg name="param_P" value="simple_loop/linear_x/P.yaml" />
<arg name="param_I" value="simple_loop/linear_x/I.yaml" />
<arg name="param_D" value="simple_loop/linear_x/D.yaml" />
<arg name="param_input" value="simple_loop/linear_x/input.yaml" />
</include>
<node name="ratey" pkg="detect_targets" type="control_compute.py" args="rate" output="screen">
<remap from="input" to="linear_y" />
<remap from="output" to="rated_y" />
</node>
<include file="$(find detect_targets)/launch/control.launch" ns="controller_linear_y">
<arg name="reset" value="/reset_pid" />
<arg name="measure" value="/rated_y" />
<arg name="param_P" value="simple_loop/linear_y/P.yaml" />
<arg name="param_I" value="simple_loop/linear_y/I.yaml" />
<arg name="param_D" value="simple_loop/linear_y/D.yaml" />
<arg name="param_input" value="simple_loop/linear_y/input.yaml" />
</include>
<node name="ratez" pkg="detect_targets" type="control_compute.py" args="rate" output="screen">
<remap from="input" to="linear_z" />
<remap from="output" to="rated_z" />
</node>
<include file="$(find detect_targets)/launch/control.launch" ns="controller_linear_z">
<arg name="reset" value="/reset_pid" />
<arg name="measure" value="/rated_z" />
<arg name="param_P" value="simple_loop/linear_z/P.yaml" />
<arg name="param_I" value="simple_loop/linear_z/I.yaml" />
<arg name="param_D" value="simple_loop/linear_z/D.yaml" />
<arg name="param_input" value="simple_loop/linear_z/input.yaml" />
</include>
<node name="rate_ang_z" pkg="detect_targets" type="control_compute.py" args="rate" output="screen">
<remap from="input" to="angular_z" />
<remap from="output" to="rated_ang_z" />
</node>
<include file="$(find detect_targets)/launch/control.launch" ns="controller_angular_z">
<arg name="reset" value="/reset_pid" />
<arg name="measure" value="/rated_ang_z" />
<arg name="param_P" value="simple_loop/angular_z/P.yaml" />
<arg name="param_I" value="simple_loop/angular_z/I.yaml" />
<arg name="param_D" value="simple_loop/angular_z/D.yaml" />
<arg name="param_input" value="simple_loop/angular_z/input.yaml" />
</include>
<node name="twister" pkg="detect_targets" type="twist_controls.py">
<remap from="control_linear_z" to="controller_linear_z/output" />
<remap from="control_angular_z" to="controller_angular_z/output" />
<remap from="control_linear_x" to="controller_linear_x/output" />
<remap from="control_linear_y" to="controller_linear_y/output" />
</node>
<node name="safe" pkg="detect_targets" type="safe_drone_teleop.py" output="screen" launch-prefix="xterm -e">
<remap from="takeoff" to="/bebop/takeoff"/>
<remap from="land" to="/bebop/land"/>
<remap from="reset" to="/bebop/reset"/>
<remap from="cmd_vel_out" to="/bebop/cmd_vel"/>
<remap from="cmd_vel_in" to="/cmd_vel"/>
</node>
<node name="view" pkg="rqt_image_view" type="rqt_image_view" args="/bebop/image_raw"/>
<node name="view_targets" pkg="rqt_image_view" type="rqt_image_view" args="/img_targets"/>
<node name="graph" pkg="rqt_graph" type="rqt_graph" output="screen"></node>
<node name="reconf" pkg="rqt_reconfigure" type="rqt_reconfigure"/>
</launch>

19
params/rate.yaml Normal file
View file

@ -0,0 +1,19 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
k: 1.0
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
refresh_time: 0.05
state: true
type: ''
state: []
k: 1.0
refresh_time: 0.05
state: []

21
params/safe.yaml Normal file
View file

@ -0,0 +1,21 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
angular: 0.5
delay: 2.0
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
angular: 0.5
delay: 2.0
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
linear: 0.5
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
state: true
type: ''
state: []
linear: 0.5
state: []

View file

@ -1,6 +1,6 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
angular: 0.5
angular: 2.0
delay: 2.0
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
@ -9,7 +9,7 @@ dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
linear: 0.05
linear: 0.5
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
@ -17,5 +17,5 @@ dictitems:
state: true
type: ''
state: []
linear: 0.05
linear: 0.5
state: []

View file

@ -0,0 +1,25 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
deriv: 1
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
deriv: 1
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
k: -0.67
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
poly_order: 2
refresh_time: 0.05
size: 19
state: true
type: ''
state: []
k: -0.67
poly_order: 2
refresh_time: 0.05
size: 19
state: []

View file

@ -0,0 +1,27 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
k: -0.8
max: 0.0
min: 0.0
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
refresh_time: 0.05
state: true
type: ''
use_max: false
use_min: false
state: []
k: -0.8
max: 0.0
min: 0.0
refresh_time: 0.05
use_max: false
use_min: false
state: []

View file

@ -0,0 +1,19 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
k: -1.1
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
refresh_time: 0.05
state: true
type: ''
state: []
k: -1.1
refresh_time: 0.05
state: []

View file

@ -0,0 +1,17 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
state: true
type: ''
value: 0.0
state: []
value: 0.0
state: []

View file

@ -0,0 +1,25 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
deriv: 1
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
deriv: 1
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
k: -0.1
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
poly_order: 2
refresh_time: 0.05
size: 11
state: true
type: ''
state: []
k: -0.1
poly_order: 2
refresh_time: 0.05
size: 11
state: []

View file

@ -0,0 +1,27 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
k: 0.0
max: 0.0
min: 0.0
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
refresh_time: 0.05
state: true
type: ''
use_max: false
use_min: false
state: []
k: 0.0
max: 0.0
min: 0.0
refresh_time: 0.05
use_max: false
use_min: false
state: []

View file

@ -0,0 +1,19 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
k: -0.07
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
refresh_time: 0.05
state: true
type: ''
state: []
k: -0.07
refresh_time: 0.05
state: []

View file

@ -0,0 +1,17 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
state: true
type: ''
value: 2.5
state: []
value: 2.5
state: []

View file

@ -0,0 +1,25 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
deriv: 1
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
deriv: 1
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
k: 0.14
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
poly_order: 2
refresh_time: 0.05
size: 11
state: true
type: ''
state: []
k: 0.14
poly_order: 2
refresh_time: 0.05
size: 11
state: []

View file

@ -0,0 +1,27 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
k: 0.0
max: 0.0
min: 0.0
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
refresh_time: 0.05
state: true
type: ''
use_max: false
use_min: false
state: []
k: 0.0
max: 0.0
min: 0.0
refresh_time: 0.05
use_max: false
use_min: false
state: []

View file

@ -0,0 +1,19 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
k: 0.27
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
refresh_time: 0.05
state: true
type: ''
state: []
k: 0.27
refresh_time: 0.05
state: []

View file

@ -0,0 +1,17 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
state: true
type: ''
value: 0.0
state: []
value: 0.0
state: []

View file

@ -0,0 +1,25 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
deriv: 1
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
deriv: 1
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
k: 0.63
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
poly_order: 2
refresh_time: 0.05
size: 11
state: true
type: ''
state: []
k: 0.63
poly_order: 2
refresh_time: 0.05
size: 11
state: []

View file

@ -0,0 +1,27 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
k: 1.52
max: 0.0
min: 0.0
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
refresh_time: 0.05
state: true
type: ''
use_max: false
use_min: false
state: []
k: 1.52
max: 0.0
min: 0.0
refresh_time: 0.05
use_max: false
use_min: false
state: []

View file

@ -0,0 +1,19 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
k: 1.2
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
refresh_time: 0.05
state: true
type: ''
state: []
k: 1.2
refresh_time: 0.05
state: []

View file

@ -0,0 +1,17 @@
!!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
dictitems:
groups: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
id: 0
name: Default
parameters: !!python/object/new:dynamic_reconfigure.encoding.Config
state: []
parent: 0
state: true
type: ''
value: 0.0
state: []
value: 0.0
state: []

View file

@ -4,6 +4,7 @@ from scipy.signal import savgol_coeffs
import numpy as np
import sys
import threading
import functools
import rospy
@ -31,12 +32,12 @@ class ControlNode(object):
if config_class is not None:
self.server = dynamic_reconfigure.server.Server(config_class, self.on_reconf)
def on_reset(self, value):
if value:
self.output = 0.0
def on_reset(self, value=None):
self.output = 0.0
def on_reconf(self, config, level):
self.refresh_time = rospy.Duration.from_sec(config["refresh_time"])
self.on_reset()
return config
def on_compute(self, value):
@ -115,7 +116,7 @@ class SaturateNode(InputControlNode):
super(SaturateNode, self).on_compute(value)
class IntegralNode(SaturateNode):
def __init__(self, k=1.0, min=None, max=None, refresh_time=0.05):
def __init__(self, k=0.0, min=None, max=None, refresh_time=0.05):
super(IntegralNode, self).__init__(min, max, refresh_time, IntegralNodeConfig)
self.k = k
@ -126,8 +127,9 @@ class IntegralNode(SaturateNode):
def on_compute(self, value):
time_ok, delta = self.check_time()
if time_ok:
self.output += value.data * delta
return super(IntegralNode, self).on_compute(value)
old_output = self.output
self.output += self.k * value.data * delta
return super(IntegralNode, self).on_compute(Float64(self.output))
class DerivativeNode(InputControlNode):
def __init__(self, k=0.05, size=9, polyorder=3, deriv=1, refresh_time=0.05):
@ -155,13 +157,12 @@ class DerivativeNode(InputControlNode):
time_ok, delta = self.check_time()
if time_ok:
self.last_points = np.concatenate([self.last_points[1:], [value.data]])
self.output = self.last_points.dot(self.filter)
self.output = self.k * self.last_points.dot(self.filter)
return super(DerivativeNode, self).on_compute(value)
def on_reset(self, value):
if value:
self.last_points = np.zeros(len(self.filter))
return super(DerivativeNode, self).on_reset(value)
def on_reset(self, value=None):
self.last_points = np.zeros(len(self.filter))
return super(DerivativeNode, self).on_reset(value)
class DifferenciateNode(InputControlNode):
def __init__(self):
@ -186,7 +187,7 @@ class InputNode(InputControlNode):
def on_reconf(self, config, level):
self.output = config["value"]
super(InputNode, self).on_compute(config["value"])
super(InputNode, self).on_compute(Float64(config["value"]))
return config
def on_compute(self, value):
@ -200,7 +201,11 @@ class SumNode(ControlNode):
self.inputs = dict()
for i in range(self.nb_topics):
topic_name = 'input_'+str(i)
self.input_topics[topic_name] = rospy.Subscriber(topic_name, Float64, lambda v: self.inputs.update(dict(topic_name=v.data)) or self.on_compute(v))
self.input_topics[topic_name] = rospy.Subscriber(topic_name, Float64, functools.partial(self.update_value, topic_name))
def update_value(self, key, value):
self.inputs.update({key:value.data})
self.on_compute(value)
def on_compute(self, value):
self.output = sum(self.inputs.values())
@ -218,6 +223,7 @@ if __name__ == '__main__':
'rate': (RateNode, False),
}
rospy.init_node('control_node', anonymous=True)
rospy.loginfo("Running node " + sys.argv[1])
try:
node_class, need_param = nodes[sys.argv[1]]
except KeyError as e:

221
scripts/safe_drone_teleop.py Executable file
View file

@ -0,0 +1,221 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import curses
import math
import rospy
import sys
import dynamic_reconfigure.server
from std_msgs.msg import String
from std_msgs.msg import Empty
from geometry_msgs.msg import Twist
from demo_teleop.cfg import SafeDroneTeleopConfig
class Status:
def __init__(self):
self.status = "landed" # "landing" "taking off" "automatic flight" "manual flight"
self.last_time = rospy.Time()
self.last_input = rospy.Time()
self.twist = Twist()
self.in_twist = Twist()
self.state_wait = 3.0 # transition between states (taking_off, landing, etc..)
self.watchdog_time = .25 # input crash security delay (no input twist => stop)
self.linear = 0.1 # initial value
self.angular = 0.5 # initial value
self.delay = 2.0 # initial value
self.status_pub = rospy.Publisher ('status', String, queue_size=1)
self.r_pub = rospy.Publisher ('reset', Empty, queue_size=1)
self.r_pid_pub = rospy.Publisher ('reset_pid', Empty, queue_size=1)
self.t_pub = rospy.Publisher ('takeoff', Empty, queue_size=1)
self.l_pub = rospy.Publisher ('land', Empty, queue_size=1)
self.twist_pub = rospy.Publisher ('cmd_vel_out', Twist, queue_size=1)
self.twist_sub = rospy.Subscriber('cmd_vel_in', Twist, self.on_twist, queue_size = 1)
self.config_srv = dynamic_reconfigure.server.Server(SafeDroneTeleopConfig, self.on_reconf)
def on_reconf(self, config, level):
self.angular = config['angular']
self.linear = config['linear']
self.delay = config['delay']
return config
def on_twist(self, ros_data):
self.in_twist = ros_data
self.last_input = rospy.Time.now()
if self.status == "automatic flight":
self.twist_pub.publish(self.in_twist)
def send_twist(self):
if self.status == "manual flight":
self.twist_pub.publish(self.twist)
def take_off(self):
if self.status == "landed" :
self.twist = Twist()
self.status = "taking off"
self.status_pub.publish(self.status)
self.r_pub.publish(Empty())
rospy.sleep(1.)
self.t_pub.publish(Empty())
self.last_time = rospy.Time.now()
def land(self):
self.last_time = rospy.Time.now()
self.twist = Twist()
self.status = "landing"
self.l_pub.publish(Empty())
def nop(self):
if self.status == "manual flight" :
time = rospy.Time.now()
if (time - self.last_time).to_sec() > self.delay :
self.status = "automatic flight"
self.r_pid_pub.publish(Empty())
elif self.status == "taking off":
time = rospy.Time.now()
if (time - self.last_time).to_sec() > self.state_wait :
self.status = "manual flight"
self.last_time = time
self.twist = Twist()
elif self.status == "landing":
time = rospy.Time.now()
if (time - self.last_time).to_sec() > self.state_wait :
self.status = "landed"
self.status_pub.publish(self.status)
self.send_twist()
def key_pressed(self):
self.last_time = rospy.Time.now()
if self.status != "manual flight":
self.twist = Twist()
if self.status == "automatic flight" :
self.status = "manual flight"
self.send_twist()
def main(stdscr):
xlevel = 0
ylevel = 0
zlevel = 0
alevel = 0
rospy.init_node('safe_drone_teleop', anonymous=True)
log_pub = rospy.Publisher ('log', String, queue_size=1)
rate = rospy.Rate(10)
keycode = -1
status = Status()
stdscr.addstr("Safe drone controller\n")
stdscr.addstr("---------------------\n")
stdscr.addstr("\n")
stdscr.addstr("Command\n")
stdscr.addstr(" - UP/DOWN : control linear x\n")
stdscr.addstr(" - LEFT/RIGHT : control linear y\n")
stdscr.addstr(" - e/r : control angular z\n")
stdscr.addstr(" - t/l : take off / land\n")
stdscr.addstr(" - PAGE UP/DOWN : elevation control\n")
stdscr.addstr(" - any key : reset of the twist\n")
# We set the "wait for a key press" period to 100 ms.
stdscr.timeout(100)
while (not rospy.is_shutdown()):
keycode = stdscr.getch() # Wait for a key press for at most 100ms
if keycode == -1 :
status.nop() # No key has been pressed, we keep current twist.
elif keycode == curses.KEY_UP :
status.key_pressed()
if xlevel == -1 :
status.twist.linear.x = 0
xlevel = 0
elif xlevel == 0:
status.twist.linear.x = status.linear
xlevel = 1
elif keycode == curses.KEY_DOWN :
status.key_pressed()
if xlevel == 0 :
status.twist.linear.x = -status.linear
xlevel = -1
elif xlevel == 1:
status.twist.linear.x = 0
xlevel = 0
elif keycode == curses.KEY_LEFT :
status.key_pressed()
if ylevel == -1 :
status.twist.linear.y = 0
ylevel = 0
elif ylevel == 0:
status.twist.linear.y = status.linear
ylevel = 1
elif keycode == curses.KEY_RIGHT :
status.key_pressed()
if ylevel == 0 :
status.twist.linear.y = -status.linear
ylevel = -1
elif ylevel == 1:
status.twist.linear.y = 0
ylevel = 0
elif keycode == curses.KEY_PPAGE :
status.key_pressed()
if zlevel == -1 :
status.twist.linear.z = 0
zlevel = 0
elif zlevel == 0:
status.twist.linear.z = status.linear
zlevel = 1
elif keycode == curses.KEY_NPAGE :
status.key_pressed()
if zlevel == 1 :
status.twist.linear.z = 0
zlevel = 0
elif zlevel == 0:
status.twist.linear.z = -status.linear
zlevel = -1
elif keycode == 101 : # e
status.key_pressed()
if alevel == -1 :
status.twist.angular.z = 0
alevel = 0
elif alevel == 0:
status.twist.angular.z = status.angular
alevel = 1
elif keycode == 114 : # r
status.key_pressed()
if alevel == 0 :
status.twist.angular.z = -status.angular
alevel = -1
elif alevel == 1:
status.twist.angular.z = 0
alevel = 0
elif keycode == 116 : # t
status.take_off()
xlevel = 0
ylevel = 0
zlevel = 0
alevel = 0
elif keycode == 108 : # l
status.land()
xlevel = 0
ylevel = 0
zlevel = 0
alevel = 0
else :
status.key_pressed()
status.twist = Twist()
xlevel = 0
ylevel = 0
zlevel = 0
alevel = 0
if status.status == "automatic flight" :
xlevel = 0
ylevel = 0
zlevel = 0
alevel = 0
status.twist = Twist()
# Starts curses (terminal handling) and run our main function.
if __name__ == '__main__':
try:
curses.wrapper(lambda w: main(w))
except rospy.ROSInterruptException:
pass