Skip to content

Commit

Permalink
Feature infinite flight (#444)
Browse files Browse the repository at this point in the history
* infinite flight example
  • Loading branch information
julienthevenoz committed Mar 18, 2024
1 parent 15529ae commit 1e8ef22
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 1 deletion.
89 changes: 89 additions & 0 deletions crazyflie_examples/crazyflie_examples/infinite_flight.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env python

from pathlib import Path

from crazyflie_py import Crazyswarm
from crazyflie_py.uav_trajectory import Trajectory
import numpy as np


def main():
swarm = Crazyswarm()
timeHelper = swarm.timeHelper
allcfs = swarm.allcfs

traj1 = Trajectory()
traj1.loadcsv(Path(__file__).parent / 'data/figure8.csv')

TIMESCALE = 1.0
for cf in allcfs.crazyflies:
cf.uploadTrajectory(0, 0, traj1)
timeHelper.sleep(1)

# pm_state : 0 = on battery 1 = charging 2 = charged 3 = low power 4 = shutdown
flight_counter = 1

while True:
print('takeoff')
allcfs.takeoff(targetHeight=1.0, duration=2.0)
timeHelper.sleep(2.5)
for cf in allcfs.crazyflies:
pos = np.array(cf.initialPosition) + np.array([0, 0, 1.0])
cf.goTo(pos, 0, 2.0)
timeHelper.sleep(2.5)

# fly figure8 until battery is low
fig8_counter = 0
status = allcfs.crazyflies[0].get_status()
# while status['battery'] > 3.8:
while status['pm_state'] == 0:
fig8_counter += 1
print(f'starting figure8 number {fig8_counter} of flight number {flight_counter}')
allcfs.startTrajectory(0, timescale=TIMESCALE)
timeHelper.sleep(traj1.duration * TIMESCALE + 2.0)
status = allcfs.crazyflies[0].get_status()
print(f'pm state : {status["pm_state"]}, battery left : {status["battery"]}')
timeHelper.sleep(1)

# not sure if useful
# check if pm = 3 just to be sure, if not abort test
if status['pm_state'] != 3:
print(f'power state is not 3 (low) but {status["pm_state"]}. Landing and aborting')
allcfs.land(targetHeight=0.06, duration=2.0)
timeHelper.sleep(3)
return 1

# now that battery is low, we try to land on the pad and see if it's charging
allcfs.land(targetHeight=0.06, duration=2.0)
timeHelper.sleep(5)
status = allcfs.crazyflies[0].get_status()

# if not charging, take off and land back again until it charges
while status['pm_state'] != 1:
print('Not charging, retrying')
allcfs.takeoff(targetHeight=1.0, duration=2.0)
timeHelper.sleep(2.5)
for cf in allcfs.crazyflies:
pos = np.array(cf.initialPosition) + np.array([0, 0, 1.0])
cf.goTo(pos, 0, 2.0)
timeHelper.sleep(2.5)
allcfs.land(targetHeight=0.06, duration=2.0)
timeHelper.sleep(5)
status = allcfs.crazyflies[0].get_status()

# now we wait until the crazyflie is charged
# while status['battery'] < 4.1:
while status['pm_state'] != 2:
print(f'Charging in progress, battery at {status["battery"]}V')
timeHelper.sleep(60)
status = allcfs.crazyflies[0].get_status()
# check if it's still charging ###not sure if this check is useful
if status['pm_state'] != 1:
print(f'charging interrupted, pm state : {status["pm_state"]}')

print('Charging finished, time to fly again')
flight_counter += 1


if __name__ == '__main__':
main()
1 change: 1 addition & 0 deletions crazyflie_examples/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ console_scripts =
cmd_full_state = crazyflie_examples.cmd_full_state:main
set_param = crazyflie_examples.set_param:main
swap = crazyflie_examples.swap:main
infinite_flight = crazyflie_examples.infinite_flight:main
35 changes: 34 additions & 1 deletion crazyflie_py/crazyflie_py/crazyflie.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# from .visualizer import visNull


from crazyflie_interfaces.msg import FullState, Position, TrajectoryPolynomialPiece
from crazyflie_interfaces.msg import FullState, Position, Status, TrajectoryPolynomialPiece
from crazyflie_interfaces.srv import GoTo, Land,\
NotifySetpointsStop, StartTrajectory, Takeoff, UploadTrajectory
from geometry_msgs.msg import Point
Expand Down Expand Up @@ -136,6 +136,9 @@ def __init__(self, node, cfname, paramTypeDict):
self.setParamsService = node.create_client(
SetParameters, '/crazyflie_server/set_parameters')
self.setParamsService.wait_for_service()
self.statusSubscriber = node.create_subscription(
Status, f'{self.prefix}/status', self.status_topic_callback, 10)
self.status = {}

# Query some settings
getParamsService = node.create_client(GetParameters, '/crazyflie_server/get_parameters')
Expand Down Expand Up @@ -699,6 +702,36 @@ def cmdPosition(self, pos, yaw=0.):
# self.setParam('ring/solidGreen', int(g * 255))
# self.setParam('ring/solidBlue', int(b * 255))

def status_topic_callback(self, msg):
"""
Call back for topic /cfXXX/status.
Update the status attribute every time a crazyflie_interfaces/msg/Status
message is published on the topic /cfXXX/status
"""
self.status = {'id': msg.header.frame_id,
'timestamp_sec': msg.header.stamp.sec,
'timestamp_nsec': msg.header.stamp.nanosec,
'supervisor': msg.supervisor_info,
'battery': msg.battery_voltage,
'pm_state': msg.pm_state,
'rssi': msg.rssi,
'num_rx_broadcast': msg.num_rx_broadcast,
'num_tx_broadcast': msg.num_tx_broadcast,
'num_rx_unicast': msg.num_rx_unicast,
'num_tx_unicast': msg.num_tx_unicast}

def get_status(self):
"""
Return the status attribute.
Status is a dictionary containing:
frame id, timestamp, supervisor info, battery voltage, pm state, rssi, nb of received or
transmitted broadcast or unicast messages. see crazyflie_interfaces/msg/Status for details
"""
# self.node.get_logger().info(f'Crazyflie.get_status() was called {self.status}')
return self.status


class CrazyflieServer(rclpy.node.Node):
"""
Expand Down

0 comments on commit 1e8ef22

Please sign in to comment.