Skip to content

Commit 75c5404

Browse files
committed
px4_offboard_demo_py: use a config file
1 parent 055b8e5 commit 75c5404

File tree

7 files changed

+93
-48
lines changed

7 files changed

+93
-48
lines changed

px4_offboard_demo_py/package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
<depend>rclpy</depend>
1111
<depend>px4_msgs</depend>
12+
<depend>ament_index_python</depend>
1213

1314
<exec_depend>ros2launch</exec_depend>
1415
<exec_depend>cdinit_ros2</exec_depend>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Configuration parameters for PX4 Offboard Demo
2+
3+
# Timer settings
4+
timer_frequency: 50.0 # Hz - frequency of timer callback
5+
timeout_sec: 0.1 # seconds - timeout for spin_once
6+
7+
# Offboard mode settings
8+
offboard_set_interval: 0.2 # seconds - interval to periodically try switching to offboard mode
9+
10+
# Arming settings
11+
arm_command_interval: 1.0 # seconds - interval between arm commands
12+
13+
# Takeoff settings
14+
takeoff_altitude: 10.0 # meters - altitude for takeoff command
15+
16+
# Velocity command settings
17+
velocity_commands:
18+
forward:
19+
duration: 4.0 # seconds - duration for forward velocity
20+
velocity: [2.0, 0.0, 0.0] # m/s - velocity in x, y, z directions
21+
zero:
22+
duration: 2.0 # seconds - duration for zero velocity
23+
velocity: [0.0, 0.0, 0.0] # m/s - velocity in x, y, z directions
24+
backward:
25+
duration: 4.0 # seconds - duration for backward velocity
26+
velocity: [-2.0, 0.0, 0.0] # m/s - velocity in x, y, z directions
27+
28+
# Position printing
29+
position_print_interval: 1.0 # seconds - interval between position prints

px4_offboard_demo_py/px4_offboard_demo_py/demo_node.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
"""ROS2 node that interacts with PX4-Autopilot using px4_msgs."""
22

3+
import os
4+
5+
import ament_index_python
6+
37
import rclpy
48
from rclpy.node import Node
59

10+
import yaml
11+
612
from .px4_communication import PX4Communication
713
from .px4_state_machine import PX4TakeoffStateMachine
814

@@ -14,14 +20,33 @@ def __init__(self):
1420
"""PX4OffboardDemoNode."""
1521
super().__init__('demo_node')
1622

23+
# Load configuration from YAML file
24+
# First try to find config file using ament resource system
25+
config_path = None
26+
try:
27+
package_share_path = ament_index_python.packages.get_package_share_directory('px4_offboard_demo_py')
28+
config_path = os.path.join(package_share_path, 'config', 'demo_config.yaml')
29+
except (ImportError, ament_index_python.packages.PackageNotFoundError):
30+
# Fallback to the old method if ament_index_python is not available
31+
config_path = os.path.join(os.path.dirname(__file__), 'config', 'demo_config.yaml')
32+
33+
try:
34+
with open(config_path, 'r', encoding='utf-8') as file:
35+
self.config = yaml.safe_load(file)
36+
self.get_logger().info(f'Configuration loaded from: {config_path}')
37+
except FileNotFoundError as exception:
38+
self.get_logger().error(f'Configuration file not found: {config_path}')
39+
raise RuntimeError(f'Configuration file not found: {config_path}') from exception
40+
1741
# Initialize PX4 communication handler (includes subscriptions)
1842
self.px4_comm = PX4Communication(self)
1943

20-
# Initialize state machine
21-
self.state_machine = PX4TakeoffStateMachine(self, self.px4_comm)
44+
# Initialize state machine with configuration
45+
self.state_machine = PX4TakeoffStateMachine(self, self.px4_comm, self.config)
2246

23-
# Create timer for sending messages (50 Hz to send constant zero velocity)
24-
self.timer = self.create_timer(0.02, self.timer_callback) # 50 Hz for faster updates
47+
# Create timer for sending messages based on config
48+
timer_period = 1.0 / self.config['timer_frequency'] # Convert frequency to period
49+
self.timer = self.create_timer(timer_period, self.timer_callback)
2550

2651
self.get_logger().info('PX4 Offboard Demo Node initialized')
2752
# Initialize takeoff_started for backward compatibility
@@ -49,9 +74,9 @@ def main(args=None):
4974
demo_node = PX4OffboardDemoNode()
5075

5176
try:
52-
# Use spin_once in a loop to check for completion
77+
# Use spin_once in a loop to check for completion, using timeout from config
5378
while rclpy.ok() and not getattr(demo_node, 'completed', False):
54-
rclpy.spin_once(demo_node, timeout_sec=0.1)
79+
rclpy.spin_once(demo_node, timeout_sec=demo_node.config['timeout_sec'])
5580
except KeyboardInterrupt:
5681
demo_node.get_logger().info('Interrupted by user')
5782
finally:

px4_offboard_demo_py/px4_offboard_demo_py/px4_communication.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def vehicle_odometry_callback(self, msg):
7070
"""Update vehicle odometry."""
7171
self.vehicle_odometry = msg
7272

73-
def should_print_position(self, current_time_sec, print_interval=1.0):
73+
def should_print_position(self, current_time_sec, print_interval=None):
7474
"""
7575
Check if we should print the position based on the time interval.
7676
@@ -81,6 +81,9 @@ def should_print_position(self, current_time_sec, print_interval=1.0):
8181
Returns:
8282
bool: True if position should be printed
8383
"""
84+
if print_interval is None:
85+
print_interval = 1.0 # default value
86+
8487
if current_time_sec - self._last_odom_print_time >= print_interval:
8588
self._last_odom_print_time = current_time_sec
8689
return True

px4_offboard_demo_py/px4_offboard_demo_py/px4_state_machine.py

Lines changed: 25 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,20 @@
55
class PX4TakeoffStateMachine:
66
"""PX4TakeoffStateMachine."""
77

8-
def __init__(self, node, px4_comm):
8+
# pylint: disable=too-many-instance-attributes
9+
10+
def __init__(self, node, px4_comm, config=None):
911
"""
1012
Initialize the state machine.
1113
1214
Args:
1315
node: The ROS2 node
1416
px4_comm: The PX4 communication handler
17+
config: Configuration dictionary loaded from YAML file
1518
"""
1619
self.node = node
1720
self.px4_comm = px4_comm
21+
self.config = config or {}
1822

1923

2024
# Define the state sequence for the complete flight operation
@@ -97,7 +101,7 @@ def _handle_waiting_for_status(self, current_time_sec):
97101
self.state_variables['enter_offboard_mode'] = {
98102
'start_time': 0,
99103
'last_offboard_set_time': 0,
100-
'offboard_set_interval': 0.2
104+
'offboard_set_interval': self.config['offboard_set_interval']
101105
}
102106
# Set the start time for the offboard transition in the next state
103107
offboard_vars = self.state_variables['enter_offboard_mode']
@@ -117,7 +121,7 @@ def _handle_enter_offboard_mode(self, current_time_sec):
117121
self.state_variables[current_state] = {
118122
'start_time': 0,
119123
'last_offboard_set_time': 0,
120-
'offboard_set_interval': 0.2 # seconds (200ms) to periodically try switching to offboard mode
124+
'offboard_set_interval': self.config['offboard_set_interval'] # seconds to periodically try switching to offboard mode
121125
}
122126

123127
offboard_vars = self.state_variables[current_state]
@@ -127,20 +131,14 @@ def _handle_enter_offboard_mode(self, current_time_sec):
127131
offboard_vars['start_time'] = current_time_sec
128132
offboard_vars['last_offboard_set_time'] = current_time_sec
129133

130-
last_offboard_set_time = offboard_vars['last_offboard_set_time']
131-
132134
# Continue sending zero velocity commands while waiting for mode switch
133135
self.px4_comm.send_zero_velocity_setpoint()
134136
self.px4_comm.set_offboard_mode() # Continue publishing offboard mode
135137

136138
# Re-send VEHICLE_CMD_DO_SET_MODE command periodically
137-
offboard_set_interval = offboard_vars['offboard_set_interval'] # Get interval from state variables
138-
if current_time_sec - last_offboard_set_time > offboard_set_interval:
139+
if current_time_sec - offboard_vars['last_offboard_set_time'] > offboard_vars['offboard_set_interval']:
139140
self.px4_comm.send_offboard_mode_command()
140-
last_offboard_set_time = current_time_sec # Update the time when command is sent
141-
142-
# Update the stored time
143-
offboard_vars['last_offboard_set_time'] = last_offboard_set_time
141+
offboard_vars['last_offboard_set_time'] = current_time_sec # Update the time when command is sent
144142

145143
# Check if the vehicle has switched to offboard mode
146144
success = (self.px4_comm.vehicle_status
@@ -166,9 +164,9 @@ def _handle_arming_vehicle(self, current_time_sec):
166164
if self.px4_comm.vehicle_status.arming_state == VehicleStatus.ARMING_STATE_ARMED:
167165
return True
168166

169-
# Re-send arm command periodically with proper throttling
167+
# Re-send arm command periodically with proper throttling using config
170168
last_arm_time = self.state_variables['arming_vehicle']['last_arm_command_time']
171-
if last_arm_time is None or current_time_sec - last_arm_time >= 1.0: # Every second
169+
if last_arm_time is None or current_time_sec - last_arm_time >= self.config['arm_command_interval']:
172170
self.px4_comm.arm_vehicle()
173171
self.state_variables['arming_vehicle']['last_arm_command_time'] = current_time_sec # Update the time when command is sent
174172

@@ -186,8 +184,8 @@ def _handle_sending_takeoff(self, current_time_sec): # pylint: disable=unused-a
186184
return True
187185

188186
if self.px4_comm.vehicle_status.nav_state != VehicleStatus.NAVIGATION_STATE_AUTO_TAKEOFF:
189-
# Send takeoff command
190-
self.px4_comm.send_takeoff_command(10.0)
187+
# Send takeoff command with altitude from config
188+
self.px4_comm.send_takeoff_command(self.config['takeoff_altitude'])
191189

192190
return False
193191

@@ -210,15 +208,11 @@ def _handle_performing_velocity_forward(self, current_time_sec):
210208
vel_vars['start_time'] = current_time_sec
211209
vel_vars['phase_start_time'] = current_time_sec
212210

213-
# Define parameters for the velocity pattern
214-
forward_duration = 4.0 # seconds for forward velocity
215-
forward_velocity = [2.0, 0.0, 0.0] # m/s in x, y, z directions
216-
217211
# Send forward velocity command
218-
self.px4_comm.send_velocity_setpoint(forward_velocity)
212+
self.px4_comm.send_velocity_setpoint(self.config['velocity_commands']['forward']['velocity'])
219213

220-
# Print position every second while executing velocity commands
221-
if self.px4_comm.should_print_position(current_time_sec):
214+
# Print position based on interval from config while executing velocity commands
215+
if self.px4_comm.should_print_position(current_time_sec, self.config['position_print_interval']):
222216
position = self.px4_comm.get_current_position()
223217
if position:
224218
x, y, z = position
@@ -227,7 +221,7 @@ def _handle_performing_velocity_forward(self, current_time_sec):
227221
self.node.get_logger().info('Position unavailable')
228222

229223
elapsed_time = current_time_sec - vel_vars['phase_start_time']
230-
if elapsed_time >= forward_duration:
224+
if elapsed_time >= self.config['velocity_commands']['forward']['duration']:
231225
return True
232226

233227
return False
@@ -251,15 +245,11 @@ def _handle_performing_velocity_zero(self, current_time_sec):
251245
vel_vars['start_time'] = current_time_sec
252246
vel_vars['phase_start_time'] = current_time_sec
253247

254-
# Define parameters for the velocity pattern
255-
zero_duration = 2.0 # seconds for zero velocity
256-
zero_velocity = [0.0, 0.0, 0.0] # m/s
257-
258248
# Send zero velocity command
259-
self.px4_comm.send_velocity_setpoint(zero_velocity)
249+
self.px4_comm.send_velocity_setpoint(self.config['velocity_commands']['zero']['velocity'])
260250

261-
# Print position every second while executing velocity commands
262-
if self.px4_comm.should_print_position(current_time_sec):
251+
# Print position based on interval from config while executing velocity commands
252+
if self.px4_comm.should_print_position(current_time_sec, self.config['position_print_interval']):
263253
position = self.px4_comm.get_current_position()
264254
if position:
265255
x, y, z = position
@@ -268,7 +258,7 @@ def _handle_performing_velocity_zero(self, current_time_sec):
268258
self.node.get_logger().info('Position unavailable')
269259

270260
elapsed_time = current_time_sec - vel_vars['phase_start_time']
271-
if elapsed_time >= zero_duration:
261+
if elapsed_time >= self.config['velocity_commands']['zero']['duration']:
272262
return True
273263

274264
return False
@@ -292,15 +282,11 @@ def _handle_performing_velocity_backward(self, current_time_sec):
292282
vel_vars['start_time'] = current_time_sec
293283
vel_vars['phase_start_time'] = current_time_sec
294284

295-
# Define parameters for the velocity pattern
296-
backward_duration = 4.0 # seconds for backward velocity
297-
backward_velocity = [-2.0, 0.0, 0.0] # m/s in x, y, z directions
298-
299285
# Send backward velocity command
300-
self.px4_comm.send_velocity_setpoint(backward_velocity)
286+
self.px4_comm.send_velocity_setpoint(self.config['velocity_commands']['backward']['velocity'])
301287

302-
# Print position every second while executing velocity commands
303-
if self.px4_comm.should_print_position(current_time_sec):
288+
# Print position based on interval from config while executing velocity commands
289+
if self.px4_comm.should_print_position(current_time_sec, self.config['position_print_interval']):
304290
position = self.px4_comm.get_current_position()
305291
if position:
306292
x, y, z = position
@@ -309,7 +295,7 @@ def _handle_performing_velocity_backward(self, current_time_sec):
309295
self.node.get_logger().info('Position unavailable')
310296

311297
elapsed_time = current_time_sec - vel_vars['phase_start_time']
312-
if elapsed_time >= backward_duration:
298+
if elapsed_time >= self.config['velocity_commands']['backward']['duration']:
313299
return True
314300

315301
return False

px4_offboard_demo_py/setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
['resource/' + package_name]),
1212
('share/' + package_name, ['package.xml']),
1313
('share/' + package_name + '/cdinit_services', ['cdinit_services/px4_offboard_demo_py_node']),
14+
('share/' + package_name + '/config', ['px4_offboard_demo_py/config/demo_config.yaml']),
1415
],
15-
install_requires=['setuptools'],
16+
install_requires=['setuptools', 'pyyaml'],
1617
zip_safe=True,
1718
maintainer='User',
1819
maintainer_email='[email protected]',

px4sitl/package.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
<buildtool_depend>cmake</buildtool_depend>
1414

15-
<exec_depend>cdinit_manager</exec_depend>
15+
<exec_depend>cdinit</exec_depend>
1616
<exec_depend>dds_agent</exec_depend>
1717
<exec_depend>px4_msgs</exec_depend>
1818
<exec_depend>ros_gz</exec_depend>

0 commit comments

Comments
 (0)