1
1
#!/usr/bin/python3
2
2
3
- import rclpy , sys , math
3
+ import rclpy , sys , math , time
4
4
import numpy as np
5
5
from enum import Enum
6
6
@@ -64,12 +64,14 @@ def __init__(self, node: Node):
64
64
self ._move_to_setpoint : PoseStamped | None = None
65
65
self ._joy_timer : None | Timer = None
66
66
self ._joy_pub = node .create_publisher (Joy , PSDKTopics .FLU_JOY .value , qos_profile = 10 )
67
+ self ._joy_ramp_time : float = 5.0
68
+ self ._setpoint_received_at : float | None = None
67
69
68
70
self .MOVE_TO_SETPOINT_TOPIC = "move_to_setpoint"
69
71
self .MOVE_TO_SETPOINT_MAX_AGE : float = 0.5 # seconds, how long we keep the move to setpoint before we consider it stale
70
- self .JOY_MAX = 0.4
72
+ self .JOY_MAX = 0.8
71
73
self .JOY_PERIOD = .1
72
- self .READY_BATTERY_PERCENTAGE = 40
74
+ self .READY_BATTERY_PERCENTAGE = 25
73
75
self .READY_HEIGHT_ABOVE_GROUND = 2
74
76
self .ERROR_BATTERY_PERCENTAGE = 15
75
77
self .ERROR_HEIGHT_ABOVE_GROUND = 1
@@ -114,22 +116,14 @@ def __init__(self, node: Node):
114
116
self ._carrying_payload : bool = False
115
117
self ._battery_percent : float | None = None
116
118
117
- self .prev_joy_left : float | None = None
118
- self .prev_joy_forw : float | None = None
119
- self .prev_joy_vert : float | None = None
120
- self .kP_horiz : float | None = None
121
- self .deriv_limit_horiz : float | None = None
122
- self .kP_vert : float | None = None
123
- self .deriv_limit_vert : float | None = None
124
-
125
119
126
120
topics = [PSDKTopics .__dict__ [t ].value for t in PSDKTopics .__members__ .keys ()]
127
121
topics = ["/Quadrotor/ " + PSDKTopics .__dict__ [t ].value for t in PSDKTopics .__members__ .keys ()]
128
122
self .log (f"Subscribed to PSDK topics: --topics { ' ' .join (topics )} " )
129
123
130
124
131
125
self ._tf_pub = node .create_publisher (TFMessage ,"/tf" ,qos_profile = 10 )
132
- self ._tf_timer = node .create_timer (0.02 , self ._publish_tf )
126
+ self ._tf_timer = node .create_timer (0.01 , self ._publish_tf )
133
127
134
128
self ._vehicle_health_pub = node .create_publisher (Int8 , SmarcTopics .VEHICLE_HEALTH_TOPIC , qos_profile = 10 )
135
129
self ._vehicle_health_timer = node .create_timer (1 , self ._publish_vehicle_health )
@@ -353,6 +347,7 @@ def status_str(self) -> str:
353
347
s += f" Vehicle Health: WAITING\n "
354
348
355
349
350
+
356
351
return s
357
352
358
353
def log (self , msg : str ):
@@ -371,6 +366,17 @@ def _move_to_setpoint_callback(self, msg: PoseStamped):
371
366
self .log (f"Move to setpoint message is older than { self .MOVE_TO_SETPOINT_MAX_AGE } s, ignoring it." )
372
367
self ._move_to_setpoint = None
373
368
return
369
+
370
+ # Check if the new setpoint is the same as the current one
371
+ if self ._move_to_setpoint is not None :
372
+ curr = self ._move_to_setpoint .pose .position
373
+ new = msg .pose .position
374
+ if abs (curr .x - new .x ) > 1e-6 and \
375
+ abs (curr .y - new .y ) > 1e-6 and \
376
+ abs (curr .z - new .z ) > 1e-6 :
377
+ self .log (f"New move to setpoint received: { format_pose_stamped (msg )} " )
378
+ self ._setpoint_received_at = time .time ()
379
+
374
380
375
381
if msg .header .frame_id != self .ODOM_FRAME :
376
382
try :
@@ -406,24 +412,20 @@ def _move_to_setpoint_callback(self, msg: PoseStamped):
406
412
velocity_as_pose_stamped .pose .position .y = self ._velocity_ground .vector .y
407
413
velocity_as_pose_stamped .pose .position .z = self ._velocity_ground .vector .z
408
414
velocity_as_pose_stamped_base_flat = do_transform_pose_stamped (velocity_as_pose_stamped , tf )
409
- self .prev_joy_forw = velocity_as_pose_stamped_base_flat .pose .position .x
410
- self . prev_joy_left = velocity_as_pose_stamped_base_flat .pose .position .y
411
- self . prev_joy_vert = velocity_as_pose_stamped_base_flat .pose .position .z
415
+ self .prev_joy_vec = np . array ([ velocity_as_pose_stamped_base_flat .pose .position .x , \
416
+ velocity_as_pose_stamped_base_flat .pose .position .y , \
417
+ velocity_as_pose_stamped_base_flat .pose .position .z ])
412
418
else :
413
- self .prev_joy_forw = 0
414
- self .prev_joy_left = 0
415
- self .prev_joy_vert = 0
419
+ self .prev_joy_vec = np .array ([0.0 , 0.0 , 0.0 ])
416
420
417
421
except Exception as e :
418
422
self .log (f"Failed to transform velocity from { self .BASE_ENU_FRAME } to { self .BASE_FLAT_FRAME } : { e } " )
419
423
self ._move_to_setpoint = None
420
424
return
421
425
422
- self .kP_horiz = self ._node .get_parameter ("p_gain_horiz" ).value
423
- self .deriv_limit_horiz = self ._node .get_parameter ("horiz_deriv_limit" ).value
424
- self .kP_vert = self ._node .get_parameter ("p_gain_vert" ).value
425
- self .deriv_limit_vert = self ._node .get_parameter ("vert_deriv_limit" ).value
426
+
426
427
self ._joy_timer = self ._node .create_timer (self .JOY_PERIOD , self ._move_with_joy )
428
+ self ._setpoint_received_at = time .time ()
427
429
self .log ("Joy timer started to move with joy." )
428
430
429
431
@@ -434,16 +436,10 @@ def cancel_joy_timer():
434
436
if self ._joy_timer is not None :
435
437
self ._joy_timer .cancel ()
436
438
self ._joy_timer = None
437
- self .prev_joy_forw = None
438
- self .prev_joy_left = None
439
- self .prev_joy_vert = None
440
- self .kP_horiz = None
441
- self .deriv_limit_horiz = None
442
- self .kP_vert = None
443
- self .deriv_limit_vert = None
439
+ self ._setpoint_received_at = None
444
440
self .log ("Joy timer cancelled." )
445
441
446
- if self ._move_to_setpoint is None :
442
+ if self ._move_to_setpoint is None or self . _setpoint_received_at is None :
447
443
self .log ("No move to setpoint set, cannot move with joy." )
448
444
return
449
445
@@ -458,16 +454,7 @@ def cancel_joy_timer():
458
454
self .log ("Not got control, cannot move with joy." )
459
455
cancel_joy_timer ()
460
456
return
461
-
462
- if self .kP_vert is None or self .kP_horiz is None or self .deriv_limit_horiz is None or self .deriv_limit_vert is None :
463
- self .log ("PID gains or limits not set, cannot move with joy." )
464
- cancel_joy_timer ()
465
- return
466
-
467
- if self .prev_joy_forw is None or self .prev_joy_left is None or self .prev_joy_vert is None :
468
- self .log ("previous conditions not set, cannot move with joy." )
469
- cancel_joy_timer ()
470
- return
457
+
471
458
472
459
tf_diff = self ._tf_buffer .lookup_transform (
473
460
target_frame = self .BASE_FLAT_FRAME ,
@@ -480,37 +467,39 @@ def cancel_joy_timer():
480
467
e_left = target_in_base .pose .position .y
481
468
e_updn = target_in_base .pose .position .z # we like mirrors around a point
482
469
483
- j_forw = max (min (self .kP_horiz * e_forw , self .JOY_MAX ), - self .JOY_MAX )
484
- j_forw_deriv = (j_forw - self .prev_joy_forw ) / self .JOY_PERIOD
485
- if (np .abs (j_forw_deriv ) > self .deriv_limit_horiz ):
486
- j_forw = max (min (self .prev_joy_forw + np .sign (j_forw_deriv ) * self .deriv_limit_horiz * self .JOY_PERIOD , self .JOY_MAX ), - self .JOY_MAX )
487
-
488
- j_left = max (min (self .kP_horiz * e_left , self .JOY_MAX ), - self .JOY_MAX )
489
- j_left_deriv = (j_left - self .prev_joy_left ) / self .JOY_PERIOD
490
- if (np .abs (j_left_deriv ) > self .deriv_limit_horiz ):
491
- j_left = max (min (self .prev_joy_left + np .sign (j_left_deriv ) * self .deriv_limit_horiz * self .JOY_PERIOD , self .JOY_MAX ), - self .JOY_MAX )
470
+ err = np .array ([e_forw , e_left , e_updn ])
471
+ now = time .time ()
472
+ time_diff = now - self ._setpoint_received_at
473
+ if time_diff < self ._joy_ramp_time :
474
+ time_diff_mult = (time_diff / self ._joy_ramp_time )
475
+ else :
476
+ time_diff_mult = 1.0
477
+ err_mag = np .linalg .norm (err ) * time_diff_mult
492
478
493
- j_vert = max (min (self .kP_vert * e_updn , self .JOY_MAX ), - self .JOY_MAX )
494
- j_vert_deriv = (j_vert - self .prev_joy_vert ) / self .JOY_PERIOD
495
- if (np .abs (j_vert_deriv ) > self .deriv_limit_vert ):
496
- j_vert = max (min (self .prev_joy_vert + np .sign (j_vert_deriv ) * self .deriv_limit_vert * self .JOY_PERIOD , self .JOY_MAX ), - self .JOY_MAX )
479
+ if np .linalg .norm (err ) > err_mag and np .linalg .norm (err ) > 0 :
480
+ err = err / np .linalg .norm (err ) * err_mag
497
481
498
- self .prev_joy_vert = j_vert
499
- self .prev_joy_forw = j_forw
500
- self .prev_joy_left = j_left
482
+ # Limit the magnitude to JOY_MAX
483
+ err = err * 0.7 #TODO make this actually competent
484
+
485
+ err_norm = np .linalg .norm (err )
486
+ if err_norm > self .JOY_MAX and err_norm > 0 :
487
+ err = err / err_norm * self .JOY_MAX
488
+
489
+ j_forw , j_left , j_updn = err .tolist ()
490
+
491
+
501
492
502
493
joy_msg = Joy ()
503
494
joy_msg .header .stamp = self .now_stamp
504
- joy_msg .axes = [j_forw , j_left , j_vert , 0.0 ] # Assuming axes: [forward, left, up/down, yaw]
495
+ joy_msg .axes = [j_forw , j_left , j_updn , 0.0 ] # Assuming axes: [forward, left, up/down, yaw]
505
496
joy_msg .buttons = []
506
497
507
498
self ._joy_pub .publish (joy_msg )
508
499
509
500
def declare_node_parameters (self ):
510
- self ._node .declare_parameter ("p_gain_horiz" , 2.5 )
511
- self ._node .declare_parameter ("p_gain_vert" , 2.5 )
512
- self ._node .declare_parameter ("horiz_deriv_limit" , .4 )
513
- self ._node .declare_parameter ("vert_deriv_limit" , .4 )
501
+ self ._node .declare_parameter ("p_gain" , 2.5 )
502
+ self ._node .declare_parameter ("deriv_limit" , .4 )
514
503
515
504
def _rc_cb (self , msg : Joy ):
516
505
# if RC is touched by user, we give up control
@@ -521,6 +510,8 @@ def _rc_cb(self, msg: Joy):
521
510
self ._release_control_srv .call_async (Trigger .Request ()).add_done_callback (
522
511
lambda future : self .log (f"Release control service called, success: { future .result ().success } , message: { future .result ().message } " )
523
512
)
513
+
514
+ # self.log(f"RC buttons: {msg.buttons}")
524
515
525
516
526
517
def _velocity_ground_callback (self , msg : Vector3Stamped ):
0 commit comments