ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

Adding take off and landing into teleop_twist_keyboard.py

asked 2017-10-24 06:21:11 -0500

jfursdon gravatar image

updated 2017-10-29 02:39:39 -0500

gvdhoorn gravatar image

I have successfully sourced and compiled so I can fly my bebop drone using the teleop_twist_keyboard python script.

However I am currently having to run a separate terminal to make the bebop land and take off. Can someone help with how to edit the python script so I can assign the keys 1 ans 2 to mean take off and land respectively.

I have tried various combinations none with any luck (in addition to the original teleop twist keyboard script)

def takeoff():
   pub = rospy.Publisher("bebop/takeoff", Empty, queue_size=10 )
   rospy.init_node('takeoff', anonymous=True)
   rate = rospy.Rate(10) # 10hz
   while not rospy.is_shutdown():
       pub.publish(Empty())
       rate.sleep()

if __name__ == '__main__':
   try:
       takeoff()
   except rospy.ROSInterruptException:
       pass

def land():
   pub = rospy.Publisher("ardrone/land", Empty, queue_size=10 )
   rospy.init_node('land', anonymous=True)
   rate = rospy.Rate(10) # 10hz
   while not rospy.is_shutdown():
       pub.publish(Empty())
       rate.sleep()

if __name__ == '__main__':
   try:
       land()
   except rospy.ROSInterruptException:
       pass
1= takeoff()
2= land()

(didnt expect this one to work )Also tried:

moveBindings = {
        'i':(1,0,0,0),
        'o':(1,0,0,-1),
        'j':(0,0,0,1),
        'l':(0,0,0,-1),
        'u':(1,0,0,1),
        ',':(-1,0,0,0),
        '.':(-1,0,0,1),
        'm':(-1,0,0,-1),
        'O':(1,-1,0,0),
        'I':(1,0,0,0),
        'J':(0,1,0,0),
        'L':(0,-1,0,0),
        'U':(1,1,0,0),
        '<':(-1,0,0,0),
        '>':(-1,-1,0,0),
        'M':(-1,1,0,0),
        't':(0,0,1,0),
        'b':(0,0,-1,0),
        '1'= rostopic pub --once [namespace]/takeoff std_msgs/Empty,
        '2'= rostopic pub --once [namespace]/land std_msgs/Empty  }`enter code here`
edit retag flag offensive close merge delete

Comments

1

This repo isn't exactly what you're looking for (it's for the AR.Drone 2.0), but it may be helpful. Also, checkout Mike Hamer's tutorial for the 2.0 as well.

jayess gravatar image jayess  ( 2017-10-24 09:09:41 -0500 )edit

Also, you said

I have tried various combinations

what are these exactly? Can you update your question with your attempts?

jayess gravatar image jayess  ( 2017-10-24 09:10:31 -0500 )edit

Thanks for the link but these do not explain how to change a python script. They are relating to configuring a joystick which I am not using. Thanks though.

jfursdon gravatar image jfursdon  ( 2017-10-24 10:17:39 -0500 )edit
1

There is a keyboard teleop node too. And as I asked earlier, can you please update your question with what you've tried.

jayess gravatar image jayess  ( 2017-10-24 10:19:20 -0500 )edit

Thanks for the update, but in order to make the question readable please use the Preformatted Text (1010101) button to properly format your code.

jayess gravatar image jayess  ( 2017-10-26 09:30:45 -0500 )edit

2 Answers

Sort by ยป oldest newest most voted
1

answered 2017-10-30 06:30:40 -0500

Alberto E. gravatar image

updated 2017-10-30 06:38:40 -0500

Hello,

I have made a couple of very simple modifications to the original script in order to achieve that. What I've done is the following. First, import the Empty message:

import roslib; roslib.load_manifest('teleop_twist_keyboard')
import rospy

from geometry_msgs.msg import Twist
from std_msgs.msg import Empty

Then, create 2 new Publishers, one for landing and the other one for taking off. And create an instance of the Empty message:

if __name__=="__main__":
        settings = termios.tcgetattr(sys.stdin)

    pub = rospy.Publisher('cmd_vel', Twist, queue_size = 1)
    rospy.init_node('teleop_twist_keyboard')
    pub2 = rospy.Publisher('drone/takeoff', Empty, queue_size = 1)
    pub3 = rospy.Publisher('drone/land', Empty, queue_size = 1)
    empty_msg = Empty()

Finally, just add 2 conditions for the new keys:

while(1):
    key = getKey()
    if key in moveBindings.keys():
        x = moveBindings[key][0]    
        y = moveBindings[key][1]    
        z = moveBindings[key][2]    
        th = moveBindings[key][3]
    elif key in speedBindings.keys():   
        speed = speed * speedBindings[key][0]   
        turn = turn * speedBindings[key][1]

        print vels(speed,turn)  
        if (status == 14):
            print msg   
        status = (status + 1) % 15

    elif key == '1':
        pub2.publish(empty_msg)
    elif key == '2':
        pub3.publish(empty_msg)

    else:
        x = 0   
        y = 0   
        z = 0   
        th = 0  
        if (key == '\x03'):
            break

    twist = Twist()
twist.linear.x = x*speed; twist.linear.y = y*speed; twist.linear.z = z*speed;
twist.angular.x = 0; twist.angular.y = 0; twist.angular.z = th*turn
pub.publish(twist)

I have also created a video showing how to do it and testing the script. Hope it helps!

edit flag offensive delete link more

Comments

Thank you very much, it worked a treat. The video really helped allow me to understand what was being done and why.

jfursdon gravatar image jfursdon  ( 2017-10-30 08:18:15 -0500 )edit
1

answered 2017-10-29 02:48:34 -0500

gvdhoorn gravatar image

updated 2017-10-29 02:53:04 -0500

Edit: I think the suggestion by @jayess is actually a very good one: the repository he links you to contains a good example of a proper keyboard teleop / controller node that you could very likely use with your specific drone as well. See mikehamer/ardrone_tutorials/src/keyboard_controller.py.


I believe your issue is that you're creating Publisher inside the callback function that handles your keypress. That is not going to work: setting up Publishers and getting Subscribers to notice them and subscribe to them is going to take some time.

You'll want to treat Publishers and Subscribers as persistent objects, that you create once, somewhere in the initialisation phase of your program, and then use inside your callback.

Second: never include any sort of blocking while inside a callback: callbacks like this are supposed to quickly process an event and then return. Including a loop of any kind will make that impossible, and may even block your entire program. With Python this is sometimes hard to detect / notice, as it may spawn N threads to process these things. In your case, that may lead to N instances of Publisher, all publishing Empty msgs at 10 Hz to the bebop/takeoff, even after you've let go of the key.

My advise would be to structure your code similar to how teleop_twist_key.py is setup already, but making sure that the Empty msg gets published by your Publisher when the key you'd like to use is pressed. You'll have to make sure that the code doesn't get to this section if your keys are pressed, because otherwise it will also publish a Twist msg, which is probably not what you want (or it could be, if you'd like to exploit the "publish all-zeros Twist if I haven't pressed any key" behaviour).

edit flag offensive delete link more

Comments

Thanks very much for the explanation. Helped a lot

jfursdon gravatar image jfursdon  ( 2017-10-30 08:19:45 -0500 )edit

Question Tools

2 followers

Stats

Asked: 2017-10-24 06:21:11 -0500

Seen: 1,959 times

Last updated: Oct 30 '17