#!/usr/bin/env python # -*- coding: utf-8 -*- # Alternate controller that is expected to work. # Copyright (C) 2017 Angel Romero, Cyrill Burgener, Marco Mueller, Philipp Friedli # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . import roslib; roslib.load_manifest('d_fall_pps') import rospy from d_fall_pps.msg import ControlCommand from std_msgs.msg import Int32 # General import import time, sys import struct import logging import rosbag from rospkg import RosPack from std_msgs.msg import Float32 from std_msgs.msg import String from std_msgs.msg import Float32MultiArray from std_msgs.msg import UInt32MultiArray from d_fall_pps.srv import Anchors # Add library #sys.path.append("lib") # CrazyFlie client imports import cflib from cflib.crazyflie import Crazyflie from cflib.crtp.crtpstack import CRTPPacket, CRTPPort import cflib.drivers.crazyradio # Logging import(* from cflib.crazyflie.log import LogConfig # Logging settings logging.basicConfig(level=logging.ERROR) # CONTROLLER_MOTOR = 2 # CONTROLLER_ANGLE = 1 # CONTROLLER_RATE = 0 TYPE_PPS_MOTORS = 6 TYPE_PPS_RATE = 7 TYPE_PPS_ANGLE = 8 RAD_TO_DEG = 57.296 # CrazyRadio states: CONNECTED = 0 CONNECTING = 1 DISCONNECTED = 2 # Commands coming CMD_RECONNECT = 0 CMD_DISCONNECT = 1 # Commands for PPSClient CMD_USE_SAFE_CONTROLLER = 1 CMD_USE_CUSTOM_CONTROLLER = 2 CMD_CRAZYFLY_TAKE_OFF = 3 CMD_CRAZYFLY_LAND = 4 CMD_CRAZYFLY_MOTORS_OFF = 5 # max Number of UWB Anchors UWB_NUM_ANCHORS = 6 rp = RosPack() record_file = rp.get_path('d_fall_pps') + '/LoggingOnboard.bag' rospy.loginfo('afdsasdfasdfsadfasdfasdfasdfasdfasdfasdf') rospy.loginfo(record_file) bag = rosbag.Bag(record_file, 'w') class PPSRadioClient: """ CrazyRadio client that recieves the commands from the controller and sends them in a CRTP package to the crazyflie with the specified address. """ def __init__(self): # Setpoints to be sent to the CrazyFlie self.roll = 0.0 self.pitch = 0.0 self.yaw = 0.0 self.motor1cmd = 0.0 self.motor2cmd = 0.0 self.motor3cmd = 0.0 self.motor4cmd = 0.0 self._status = DISCONNECTED self.link_uri = "" self.status_pub = rospy.Publisher(node_name + '/CrazyRadioStatus', Int32, queue_size=1) self.PPSClient_command_pub = rospy.Publisher('PPSClient/Command', Int32, queue_size=1) time.sleep(1.0) # Initialize the CrazyFlie and add callbacks self._init_cf() # Connect to the Crazyflie self.connect() def _init_cf(self): self._cf = Crazyflie() # Add callbacks that get executed depending on the connection _status. self._cf.connected.add_callback(self._connected) self._cf.disconnected.add_callback(self._disconnected) self._cf.connection_failed.add_callback(self._connection_failed) self._cf.connection_lost.add_callback(self._connection_lost) self.change_status_to(DISCONNECTED) """ --------------------------------------- Logging functions --------------------------------------- """ def _start_logging(self): self.init_log_battery() self.init_log_rpy() self.init_log_uwb() self.UWBUpdateCallback(1) # if enableUWB: # self.init_log_uwb() # self.init_log_rpy() def _stop_logging(self): self.stop_log_battery() self.delete_log_uwb() slef.delete_log_rpy() # if enableUWB: # self.stop_log_uwb() # self.stop_log_rpy() def _logging_error(self, logconf, msg): rospy.logerr("[CrazyRadio] Error when logging %s", logconf.name) ### Battery log def init_log_battery(self): global battery_polling_period battery_polling_period = rospy.get_param(ros_namespace + "/CrazyRadio/battery_polling_period") self.batLog = LogConfig("BatteryLog", battery_polling_period) # second variable is period in ms self.batLog.add_variable("pm.vbat", "float"); self._cf.log.add_config(self.batLog) if self.batLog.valid: self.batLog.data_received_cb.add_callback(self._vbat_received_callback) self.batLog.error_cb.add_callback(self._logging_error) rospy.loginfo("[CrazyRadio] batLog valid") else: rospy.logwarn("[CrazyRadio] batLog invalid") self.batLog.start() rospy.loginfo("[CrazyRadio] batLog started") def _vbat_received_callback(self, timestamp, data, batLog): #print "log of stabilizer and battery: [%d][%s]: %s" % (timestamp, logconf.name, data) batteryVolt = Float32() batteryVolt.data = data["pm.vbat"] bag.write('batteryVoltage', batteryVolt) #publish battery voltage for GUI #cfbattery_pub.publish(std_msgs.Float32(batteryVolt.data)) #print "batteryVolt: %s" % batteryVolt cfbattery_pub.publish(batteryVolt) def stop_log_battery(self): self.batLog.stop() rospy.loginfo("[CrazyRadio] batLog stopped") self.batLog.delete() rospy.loginfo("[CrazyRadio] batLog deleted") ### UWB log def init_log_uwb(self): polling_period = rospy.get_param(ros_namespace + "/CrazyRadio/positioning_polling_period") self.anchorLog = LogConfig("AnchorDistances", polling_period) for i in range(UWB_NUM_ANCHORS): self.anchorLog.add_variable("UWB_Anchor_Pos.anchor" + str(i), "uint32_t"); self._cf.log.add_config(self.anchorLog) if self.anchorLog.valid: self.anchorLog.data_received_cb.add_callback(self._anchors_received_callback) self.anchorLog.error_cb.add_callback(self._logging_error) rospy.loginfo("[CrazyRadio] anchorLog valid") else: rospy.logwarn("[CrazyRadio] anchorLog invalid") def start_log_uwb(self): self.anchorLog.start() self.anchorLog._set_started(True) rospy.loginfo("[CrazyRadio] anchorLog started") def _anchors_received_callback(self, timestamp, data, anchorDist): dist = UInt32MultiArray() dist.data = [] for i in range(UWB_NUM_ANCHORS): dist.data.insert(i, data["UWB_Anchor_Pos.anchor" + str(i)]) uwb_location_pub.publish(dist) #bag.write('anchorTime', dist) # needs a lot of time # for debugging #for i in range(UWB_NUM_ANCHORS): # rospy.loginfo("Anchor " + str(i) + ": " + str(dist.data[i])) def stop_log_uwb(self): self.anchorLog._set_started(False) self.anchorLog.stop() rospy.loginfo("[CrazyRadio] anchorLog stopped") def delete_log_uwb(self): if (self.anchorLog._get_started()): self.stop_log_uwb() self.anchorLog.delete() rospy.loginfo("[CrazyRadio] anchorLog deleted") ### RPY log def init_log_rpy(self): polling_period = rospy.get_param(ros_namespace + "/CrazyRadio/positioning_polling_period") self.rpyLog = LogConfig("RPY", polling_period) self.rpyLog.add_variable("stabilizer.roll", "float"); self.rpyLog.add_variable("stabilizer.pitch", "float"); self.rpyLog.add_variable("stabilizer.yaw", "float"); self._cf.log.add_config(self.rpyLog) if self.rpyLog.valid: self.rpyLog.data_received_cb.add_callback(self._rpy_received_callback) self.rpyLog.error_cb.add_callback(self._logging_error) rospy.loginfo("[CrazyRadio] rpyLog valid") else: rospy.logwarn("[CrazyRadio] rpyLog invalid") def start_log_rpy(self): self.rpyLog.start() self.rpyLog._set_started(True) rospy.loginfo("[CrazyRadio] rpyLog started") def _rpy_received_callback(self, timestamp, data, rpy): rpy_data = Float32MultiArray() rpy_data.data = [data["stabilizer.roll"],data["stabilizer.pitch"],data["stabilizer.yaw"]] rpy_pub.publish(rpy_data) #bag.write('RPY', rpy_data) # needs a lot of time # for debugging #rospy.loginfo("Roll: %f\nPitch: %f\nYaw: %f", rpy_data.data[0], rpy_data.data[1], rpy_data.data[2]) def stop_log_rpy(self): self.rpyLog._set_started(False) self.rpyLog.stop() rospy.loginfo("[CrazyRadio] rpyLog stopped") def delete_log_rpy(self): if (self.rpyLog._get_started()): self.stop_log_rpy() self.rpyLog.delete() rospy.loginfo("[CrazyRadio] rpyLog deleted") """ --------------------------------------- Callback functions --------------------------------------- """ def _connected(self, link_uri): """ This callback is executed as soon as the connection to the quadrotor is established. """ self.change_status_to(CONNECTED) # change state to motors OFF cf_client.PPSClient_command_pub.publish(CMD_CRAZYFLY_MOTORS_OFF) rospy.loginfo("[CrazyRadio] Connection to %s successful: " % link_uri) # Config for Logging self._start_logging() def _disconnected(self, link_uri): """Callback when the Crazyflie is disconnected (called in all cases)""" self.change_status_to(DISCONNECTED) rospy.logwarn("[CrazyRadio] Disconnected from %s" % link_uri) # change state to motors OFF self.PPSClient_command_pub.publish(CMD_CRAZYFLY_MOTORS_OFF) self._stop_logging() def _connection_failed(self, link_uri, msg): """Callback when connection initial connection fails (i.e no Crazyflie at the specified address)""" self.change_status_to(DISCONNECTED) rospy.logerr("[CrazyRadio] Connection to %s failed: %s" % (link_uri, msg)) def _connection_lost(self, link_uri, msg): """Callback when disconnected after a connection has been made (i.e Crazyflie moves out of range)""" self.change_status_to(DISCONNECTED) rospy.logerr("[CrazyRadio] Connection to %s lost: %s" % (link_uri, msg)) def UWBUpdateCallback(self, data): """Callback for change in UWB Settings""" # TODO: Tiago? Add command to CF to enable/disable ranging rospy.wait_for_service('/UWBManagerService/UWBData') try: uwbdataproxy = rospy.ServiceProxy('/UWBManagerService/UWBData',Anchors) resp = uwbdataproxy(0,0,0) if (resp.enableUWB == False): if (self.anchorLog._get_started()): self.stop_log_uwb() if (self.rpyLog._get_started): self.stop_log_rpy() else: if not (self.anchorLog._get_started()): self.start_log_uwb() if not (self.rpyLog._get_started()): self.start_log_rpy() except rospy.ServiceException, e: rospy.logerr("[CrazyRadio] Unable to activate Loggings from Service"); """ --------------------------------------- CrazyRadio interface functions --------------------------------------- """ def change_status_to(self, new_status): print "status changed to: %s" % new_status self._status = new_status self.status_pub.publish(new_status) def get_status(self): return self._status def update_link_uri(self): self.link_uri = "radio://" + rospy.get_param("~crazyFlieAddress") def connect(self): # update link from ros params self.update_link_uri() print "Connecting to %s" % self.link_uri self.change_status_to(CONNECTING) rospy.loginfo("connecting...") self._cf.open_link(self.link_uri) def disconnect(self): print "Motors OFF" self._send_to_commander_motor(0, 0, 0, 0) # change state to motors OFF self.PPSClient_command_pub.publish(CMD_CRAZYFLY_MOTORS_OFF) time.sleep(0.1) print "Disconnecting from %s" % self.link_uri self._cf.close_link() self.change_status_to(DISCONNECTED) def _send_to_commander_motor(self, cmd1, cmd2, cmd3, cmd4): pk = CRTPPacket() pk.port = CRTPPort.COMMANDER_GENERIC pk.data = struct.pack('