ArDrone can not takeoff if Publisher is call within a Class

Hello everyone,

I got an error in Unit 5: Actions

I tried to create a Class that covers all Ardrone behavior like Takeoff, Land, TakePicture. The problem is that if I call the takeoff() function of the class, the ARDrone does nothings. It only takeoff when the publish command is executed directly in the main function.

Here is my code for reference:

#!/usr/bin/env python

import rospy as ros
import actionlib as alib 
from geometry_msgs.msg import Twist 
from ardrone_as.msg import (
    ArdroneAction, 
    ArdroneResult, 
    ArdroneGoal,
    ArdroneFeedback)

from std_msgs.msg import Empty


import time  

class ArdroneController():

    def __init__(self):
        self.velController = ros.Publisher('/cmd_vel', Twist, queue_size = 1)
        self.velCommand = Twist()   
        self.rate = ros.Rate(1)
        self.is_airbone = False # 0: Landing 1:Airbone
        self.camera = alib.SimpleActionClient('/ardrone_action_server', ArdroneAction)
        self.camera.wait_for_server()
        ros.on_shutdown(self._shutdownhook)
        self.camera_timer = ArdroneGoal()
        
    def _shutdownhook(self):
        ros.loginfo('Terminate Drone operation')
        if self.is_airbone:
            self.land()

    def investigate(self):
        if not self.is_airbone:
            self.takeoff()
        self.camera_timer.nseconds = 10.
        self.camera.send_goal(self.camera_timer, feedback_cb = self._camera_callback) 

    def _camera_callback(self, feedback):
        pass
        # velMess.linear.x = 2.0 
        # velMess.angular.x = 0.1 
        # velMess.angular.z = 0.2

        # velPubl.publish(velMess)

    def takeoff(self):
        message = Empty()
        publisher = ros.Publisher('/drone/takeoff', Empty, queue_size = 1)
        ros.loginfo("Taking Off ...")
        i = 0
        while not i == 3:
            publisher.publish(message)
            time.sleep(1.)
            i +=1
        self.is_airbone = True
            
        # del publisher, message
        ros.loginfo('Taken-Off !') 
                
    def land(self):
        message = Empty()
        publisher = ros.Publisher('/drone/land', Empty, queue_size = 1)
        while self.is_airbone:
            ros.loginfo('Landing ...')
            connections = publisher.get_num_connections()
            if connections > 0:
                publisher.publish(message)
                self.is_airbone = False
                break
        # del publisher, message
        ros.loginfo('Landed !') 

if __name__ == "__main__":
    ros.init_node('ardrone_client_node')
    controller = ArdroneController()
    try:
        controller.takeoff()
    except ros.ROSInterruptException:
        pass

    time.sleep(5)
    # controller.land()

    # message = Empty()
    # publisher = ros.Publisher('/drone/takeoff', Empty, queue_size = 1)
        
    # ros.loginfo("Taking Off ...")
    # for i in range(3):
        
    #     publisher.publish(message)
    #     time.sleep(1.)
        
    # # del publisher, message
    # ros.loginfo('Taken-Off !')

Hi @qhuy.phm,
welcome to the community :slight_smile: The code you posted is just the action CLIENT, is your action SERVER running in a seperate terminal? If yes, and it doesnt work, please post your server code

Hi @simon.steinmann91,

I’m sorry to confuse you. In my code, there are only Publisher and Subscriber implemented, I haven’t touch the Action part yet.
In order to take-off, I publish an Empty message to the topic /drone/takeoff. It works nicely when executed in the main program (below if name == “main”), but hads no effect when call within class ( ArdroneController.takeoff() )

Do you get this in your terminal?

ros.loginfo("Taking Off ...")

meaning, is the function called or not? Perhaps you wanna add a print() to you exception below, or not use Try at all.

I even got the “Taken-Off” notification. But the drone did not move an inch :exploding_head:

You could try a publish loop like this for the takeoff message as well. It ensures that it is really sent. Also check with rostopic echo /drone/takeoff whether the message gets sent