Bebop Control Module¶
Parrot Bebop 2 control via the ros2_bebop_driver ROS 2 package, for velocity-based flight.
At a glance¶
import nectar
from nectar.control import DroneFactory, BebopConfig
nectar.init()
drone = DroneFactory.create("bebop", BebopConfig())
drone.takeoff() # fixed preset height (altitude arg ignored)
drone.move_velocity(vx=0.3, duration=2.0) # body-frame, normalized [-1, 1]
drone.land()
nectar.shutdown()
Capabilities¶
BebopDrone.capabilities declares VELOCITY_BODY (body-frame move_velocity via cmd_vel) and NATIVE_RTL (navigate_home). It does not support position control, GPS, vision pose, parameters, or companion-side navigation. Query with drone.supports(Capability.VELOCITY_BODY).
Behavior specific to the Bebop hardware:
- Velocity is body-frame only, normalized to
[-1, 1];WORLD/TAKEOFFreferences are not supported. - Takeoff altitude is fixed — the
altitudeargument totakeoff()is ignored (the Bebop climbs to its own preset height; adjust afterward withmove_velocity(vz=...)). move_to()/move_to_gps()raiseCapabilityNotSupportedError(no onboard positioning — no GPS, no companion PID).connect()only verifies thebebop_driverprocess is running; there is no flight-controller handshake.rtl()publishes the autoflightnavigate_homecommand; withland=Trueit waits a fixed delay for the maneuver (it does not callland()).
Architecture¶
classDiagram
class BebopDrone {
-_takeoff_pub Publisher~Empty~
-_land_pub Publisher~Empty~
-_vel_pub Publisher~Twist~
-_flip_pub Publisher~UInt8~
-_gimbal_pub Publisher~Vector3~
-_emergency_pub Publisher~Empty~
-_flattrim_pub Publisher~Empty~
-_photo_pub Publisher~Bool~
-_navigate_home_pub Publisher~Empty~
+config BebopConfig
+node Node
+is_ready bool
+obstacle_manager ObstacleManager
+from_config(config, executor)$ BebopDrone
+connect() bool
+disconnect()
+arm() bool
+disarm() bool
+takeoff(altitude) bool
+land(timeout) bool
+move_velocity(vx, vy, vz, vyaw, duration, reference)
+move_to() CapabilityNotSupportedError
+move_to_gps() CapabilityNotSupportedError
+emergency_stop()
+rtl(altitude, precision, method, land) bool
+flip(direction)
+camera_control(tilt, pan)
+snapshot()
+flat_trim()
-_setup_publishers()
-_get_driver_name() str
-_start_driver() bool
}
class BebopConfig {
<<dataclass>>
+name str
+start_driver bool
+ip str
+namespace str
}
class BaseDrone {
<<abstract>>
+add_obstacle_detector()
+enable_obstacle_detector()
+cleanup()
}
BaseDrone <|-- BebopDrone
BebopDrone o-- BebopConfig
Configuration¶
from nectar.control import DroneFactory, BebopConfig
config = BebopConfig(
name="bebop_drone",
start_driver=True, # auto-start the ROS 2 driver on init
ip="192.168.42.1", # Bebop WiFi IP
namespace="bebop", # ROS 2 topic namespace prefix
)
drone = DroneFactory.create("bebop", config)
The Bebop creates its own WiFi network — connect to Bebop2-XXXXXX (default IP 192.168.42.1) before launching the driver.
Control API¶
Velocity Control¶
drone.move_velocity(
vx=0.0, # forward (+) / backward (-), normalized [-1, 1]
vy=0.0, # left (+) / right (-), normalized [-1, 1]
vz=0.0, # up (+) / down (-), normalized [-1, 1]
vyaw=0.0, # CCW (+) / CW (-), normalized [-1, 1]
duration=None, # None = single publish; float = republish at 30 Hz for the duration
reference=MoveReference.BODY, # BODY only
)
All inputs are clamped to [-1, 1].
Flight Operations¶
drone.takeoff(altitude=1.5) # altitude ignored (fixed height)
drone.land(timeout=30.0)
drone.rtl(land=True) # autoflight navigate_home
drone.emergency_stop() # reset command (hard stop)
Bebop-Specific Features¶
drone.flip(0) # 0=Front, 1=Back, 2=Right, 3=Left
drone.camera_control(tilt=-45.0, pan=15.0) # degrees; tilt +down/-up, pan +left/-right
drone.snapshot() # capture a photo
drone.flat_trim() # IMU calibration (on a flat, level surface)
ROS 2 Topics¶
All topics use the configured namespace prefix (default /bebop):
| Topic | Type | Purpose |
|---|---|---|
/{ns}/takeoff |
Empty | Trigger takeoff |
/{ns}/land |
Empty | Trigger landing |
/{ns}/cmd_vel |
Twist | Velocity commands (linear.x/y/z, angular.z, each [-1, 1]) |
/{ns}/flip |
UInt8 | Execute flip maneuver |
/{ns}/move_camera |
Vector3 | Gimbal control (x=tilt, y=pan) |
/{ns}/reset |
Empty | Emergency stop / reset |
/{ns}/flattrim |
Empty | IMU calibration |
/{ns}/photo |
Bool | Capture photo |
/{ns}/autoflight/navigate_home |
Empty | RTL command |
Installation¶
Automated (Nectar):
Installs the apt dependencies, clones ros2_parrot_arsdk and ros2_bebop_driver into the workspace if missing, and builds them in order (applying the FFmpeg patch below). The manual steps are equivalent:
sudo apt install ros-${ROS_DISTRO}-camera-info-manager ros-${ROS_DISTRO}-image-transport \
ros-${ROS_DISTRO}-cv-bridge libavdevice-dev libavahi-client-dev python-is-python3
cd ~/ros2_ws/src
git clone https://github.com/jeremyfix/ros2_parrot_arsdk.git
git clone https://github.com/jeremyfix/ros2_bebop_driver.git
cd ~/ros2_ws
colcon build --packages-select ros2_parrot_arsdk
colcon build --packages-select ros2_bebop_driver --symlink-install
python-is-python3is required because the ARSDK Alchemy build invokespython, which is absent by default on Ubuntu 24.04.- On Ubuntu 24.04 (FFmpeg 5/6),
avcodec_find_decoder()returnsconst AVCodec*, soAVCodec *p_codec_must becomeconst AVCodec *p_codec_ininclude/ros2_bebop_driver/video_decoder.hpp.make drone-bebopapplies this patch automatically.
Manual launch (when start_driver=False):
Usage Example¶
import nectar
from nectar.control import DroneFactory, BebopConfig
nectar.init()
drone = DroneFactory.create("bebop", BebopConfig(ip="192.168.42.1"))
drone.connect() # verifies the bebop_driver process
drone.takeoff(altitude=1.5) # fixed height
drone.move_velocity(vx=0.3, duration=2.0) # forward 2s
drone.move_velocity(vyaw=0.5, duration=1.0) # rotate CCW 1s
drone.flip(0) # front flip
drone.rtl(land=True) # navigate home