Skip to content

Commit 1475fca

Browse files
authored
Merge pull request #186 from ignaciotb/humble
Latest assisted diving from Sam
2 parents bf72c66 + 3c74676 commit 1475fca

File tree

9 files changed

+234
-8
lines changed

9 files changed

+234
-8
lines changed

.gitmodules

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
path = vehicles/hardware/dji/psdk_ros2
4949
url = https://gitr.sys.kth.se/smarc-project/dji_psdk_wrapper.git
5050
branch = smarc
51-
5251
[submodule "utilities/serial_ping_pkg"]
5352
path = utilities/serial_ping_pkg
5453
url = https://github.com/NinjaTuna007/serial_ping_pkg.git

behaviours/sam_diving_controller/config/sam_diving_controller_config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
/*/diving_node:
33
ros__parameters:
4-
view_rate: 0.1
4+
view_rate: 0.2
55
model_rate: 0.1
66
controller_rate: 0.1
77
vbs_pid_kp: 20.0

behaviours/sam_diving_controller/sam_diving_controller/JoyNode.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from .DiveSub import DiveSub
99
from .DiveController import DepthJoyControllerPID
1010
from .ConveniencePub import ConveniencePub
11+
from .ParamUtils import DivingModelParam
1112

1213
from rclpy.executors import MultiThreadedExecutor
1314

@@ -31,10 +32,11 @@ def joy_depth():
3132
dive_sub_rate = node.get_parameter('dive_sub_rate').get_parameter_value().double_value
3233

3334
convenience_pub_rate = node.get_parameter('convenience_rate').get_parameter_value().double_value
34-
35-
dive_pub = SAMDivePub(node)
36-
dive_sub = DiveSub(node, dive_pub)
37-
dive_controller = DepthJoyControllerPID(node, dive_pub, dive_sub, dive_controller_rate)
35+
36+
param = DivingModelParam(node).get_param()
37+
dive_sub = DiveSub(node, param)
38+
dive_pub = SAMDivePub(node, dive_sub, param)
39+
dive_controller = DepthJoyControllerPID(node, dive_pub, dive_sub,param, dive_controller_rate)
3840

3941
convenience_pub = ConveniencePub(node, dive_sub, dive_controller)
4042

external_equipment/sam_joy_controllers/sam_joy_controllers/sam_joy_xbox/launch/joy_depth_control.launch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<group>
88
<push-ros-namespace namespace="$(var robot_name)"/>
99

10-
<node pkg="sam_dead_reckoning" exec="depth_node" name="depth_node" output="screen">
10+
<node pkg="sam_joy_xbox" exec="depth_node" name="depth_node" output="screen">
1111
<param name="robot_name" value="$(var robot_name)" />
1212
<param name="simulation" value="false" />
1313
<param name="use_sim_time" value="false" />
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
#!/usr/bin/env python
2+
3+
import rclpy
4+
from rclpy.node import Node
5+
6+
from sensor_msgs.msg import FluidPressure
7+
from geometry_msgs.msg import PoseWithCovarianceStamped
8+
9+
# Topics
10+
from sam_msgs.msg import Topics as SamTopics
11+
from dead_reckoning_msgs.msg import Topics as DRTopics
12+
13+
# Frames/Links
14+
from sam_msgs.msg import Links as SamLinks
15+
16+
try:
17+
from .helpers.ros_helpers import rcl_time_to_stamp
18+
except ImportError:
19+
from helpers.ros_helpers import rcl_time_to_stamp
20+
21+
22+
class Press2Depth(Node):
23+
24+
def __init__(self):
25+
super().__init__("press_to_depth_node")
26+
self.get_logger().info("Starting node defined in press_to_depth.py")
27+
28+
# ===== Declare parameters =====
29+
self.declare_node_parameters()
30+
31+
self.robot_name = self.get_parameter("robot_name").value
32+
33+
self.odom_frame = self.get_parameter('odom_frame').value
34+
35+
self.base_frame = f"{self.robot_name}_{SamLinks.BASE_LINK}"
36+
self.press_frame = f"{self.robot_name}_{SamLinks.PRESS_LINK}" # Unused
37+
# Removed depth frame
38+
39+
self.subs = self.create_subscription(msg_type=FluidPressure, topic="core/vbs_tank_pressure",
40+
callback=self.depthCB, qos_profile=10)
41+
42+
self.pub = self.create_publisher(msg_type=PoseWithCovarianceStamped, topic=DRTopics.DR_DEPTH_POSE_TOPIC,
43+
qos_profile=10)
44+
45+
self.depth_msg = PoseWithCovarianceStamped()
46+
self.depth_msg.header.frame_id = self.odom_frame
47+
self.depth_msg.pose.covariance = [100., 0.0, 0.0, 0.0, 0.0, 0.0,
48+
0.0, 100., 0.0, 0.0, 0.0, 0.0,
49+
0.0, 0.0, 0.1, 0.0, 0.0, 0.0,
50+
0.0, 0.0, 0.0, 0.01, 0.0, 0.0,
51+
0.0, 0.0, 0.0, 0.0, 0.01, 0.0,
52+
0.0, 0.0, 0.0, 0.0, 0.0, 0.01]
53+
54+
self.depth_msg.pose.pose.orientation.w = 1.
55+
56+
# TODO is there a reason to have two listeners?
57+
# HAHA is there a reason for even one?
58+
# self.listener_odom = tf.TransformListener() # remove
59+
# self.listener_press = tf.TransformListener() # remove
60+
self.x_base_depth = 0.580
61+
62+
# try:
63+
# (trans,quaternion) = self.listener_press.lookupTransform(self.base_frame, self.depth_frame, rospy.Time(10))
64+
65+
# except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
66+
# print('Could not get tf base to depth.')
67+
68+
def declare_node_parameters(self):
69+
"""
70+
Declare the parameters for the node
71+
"""
72+
73+
# TODO This might be a bad way to set defaults
74+
# allows for me to run from the terminal directly for test
75+
default_robot_name = 'sam0'
76+
self.declare_parameter("robot_name", default_robot_name)
77+
78+
self.declare_parameter('odom_frame', 'odom')
79+
80+
# def depthCB_old(self, press_msg):
81+
# try:
82+
#
83+
# # # depth_abs is positive, must be manually negated
84+
# depth_abs = - self.pascal_pressure_to_depth(press_msg.fluid_pressure)
85+
# # rospy.loginfo("Depth abs %s", depth_abs)
86+
# # rospy.loginfo("Fluid press %s", press_msg.fluid_pressure)
87+
#
88+
# if press_msg.fluid_pressure > 90000. and press_msg.fluid_pressure < 500000.:
89+
# self.depth_msg.header.stamp = rospy.Time.now()
90+
# self.depth_msg.pose.pose.position.z = depth_abs # = [0., 0., 2.]
91+
# self.pub.publish(self.depth_msg)
92+
#
93+
# except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
94+
# rospy.logerr("Depth transform missing tf")
95+
96+
def depthCB(self, press_msg):
97+
"""
98+
callback for converting pressure message into a depth.
99+
"""
100+
# depth_abs is positive, must be manually negated
101+
depth_abs = - self.pascal_pressure_to_depth(press_msg.fluid_pressure)
102+
# rospy.loginfo("Depth abs %s", depth_abs)
103+
# rospy.loginfo("Fluid press %s", press_msg.fluid_pressure)
104+
105+
if press_msg.fluid_pressure > 90000. and press_msg.fluid_pressure < 500000.:
106+
self.depth_msg.header.stamp = rcl_time_to_stamp(self.get_clock().now())
107+
self.depth_msg.pose.pose.position.z = depth_abs # = [0., 0., 2.]
108+
self.pub.publish(self.depth_msg)
109+
110+
def pascal_pressure_to_depth(self, pressure):
111+
"""
112+
Convert pressure in pascal to depth in meters
113+
114+
What sensor is this for? The offset by 1 feels a little weird.
115+
116+
P = pgh
117+
P: pascals, kg/ms^2
118+
p: density of water, kg/m^3
119+
g: accel due to gravity, m/s^2
120+
h: height of water column, m
121+
122+
p(fresh) = 997.0 # random internet value
123+
p(salt) = 1023.6 # random internet value
124+
g(stockholm) = 9.818
125+
"""
126+
# TODO check this
127+
return 10. * ((pressure / 100000.) - 1.) # 117000 -> 1.7
128+
129+
def simulated_pressure_to_depth(self, pressure: float) -> float:
130+
"""
131+
Convert pressure from simulator in pascals to depth in meters.
132+
133+
General:
134+
pressure = density * gravity * depth
135+
136+
Unity:
137+
Unity uses a value of 9806.65 to convert from depth to pressure
138+
pressure = 9806.65 * depth
139+
"""
140+
depth_to_pressure = 9806.65
141+
return pressure / depth_to_pressure
142+
143+
144+
def main(args=None):
145+
rclpy.init(args=args)
146+
depth_node = Press2Depth()
147+
try:
148+
rclpy.spin(depth_node)
149+
except KeyboardInterrupt:
150+
pass
151+
152+
153+
if __name__ == "__main__":
154+
main()

external_equipment/sam_joy_controllers/sam_joy_controllers/sam_joy_xbox/setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
entry_points={
2525
'console_scripts': [
2626
'sam_joy_xbox = sam_joy_xbox.controller:main',
27+
'depth_node = sam_joy_xbox.press_to_depth:main',
2728
],
2829
},
2930
)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#!/usr/bin/env python3
2+
3+
import rclpy
4+
from rclpy.node import Node
5+
from sam_msgs.msg import ThrusterAngles, Topics
6+
import math
7+
from smarc_msgs.msg import ThrusterRPM
8+
9+
class CircularThrustVectorPublisher(Node):
10+
11+
def __init__(self):
12+
super().__init__('circular_thrust_vector_publisher')
13+
14+
# Publisher for thrust vector angles
15+
self.vector_pub = self.create_publisher(
16+
ThrusterAngles,
17+
"/sam/core/thrust_vector_cmd",
18+
qos_profile=1
19+
)
20+
21+
self.thrust1_pub = self.create_publisher(ThrusterRPM, "/sam/core/thruster1_cmd", qos_profile=1)
22+
self.thrust2_pub = self.create_publisher(ThrusterRPM, "/sam/core/thruster2_cmd", qos_profile=1)
23+
24+
# Timer to update and send commands
25+
self.timer_period = 0.1 # 10 Hz
26+
self.timer = self.create_timer(self.timer_period, self.timer_callback)
27+
28+
# Internal state for angle calculation
29+
self.t = 0.0
30+
self.get_logger().info("Circular thrust vector publisher started.")
31+
32+
def timer_callback(self):
33+
# Circle radius in radians
34+
radius = 0.1 # Must match actuator limits from your original code
35+
frequency = 0.2 # Hz, how many full cycles per second
36+
omega = 2 * math.pi * frequency
37+
38+
# Compute current angle vector (simple circular motion)
39+
horizontal = radius * math.cos(omega * self.t)
40+
vertical = radius * math.sin(omega * self.t)
41+
42+
# Create and publish message
43+
msg = ThrusterAngles()
44+
msg.header.stamp = self.get_clock().now().to_msg()
45+
msg.thruster_horizontal_radians = horizontal
46+
msg.thruster_vertical_radians = vertical
47+
self.vector_pub.publish(msg)
48+
49+
rpm_msg = ThrusterRPM()
50+
rpm_msg.rpm = 400
51+
self.thrust1_pub.publish(rpm_msg)
52+
rpm_msg.rpm = 400
53+
self.thrust2_pub.publish(rpm_msg)
54+
55+
self.get_logger().info(f"Published vector: h={horizontal:.3f}, v={vertical:.3f}", throttle_duration_sec=1)
56+
57+
self.t += self.timer_period
58+
59+
def main(args=None):
60+
rclpy.init(args=args)
61+
node = CircularThrustVectorPublisher()
62+
try:
63+
rclpy.spin(node)
64+
except KeyboardInterrupt:
65+
pass
66+
node.destroy_node()
67+
rclpy.shutdown()
68+
69+
if __name__ == '__main__':
70+
main()

external_equipment/sam_joy_controllers/sam_joy_teleop/setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
entry_points={
2222
'console_scripts': [
2323
'teleop_node = sam_joy_teleop.teleop_node:main',
24+
'test_thrust_node = sam_joy_teleop.test_thrust_vec:main',
2425
],
2526
},
2627
)

utilities/serial_ping_pkg

Submodule serial_ping_pkg deleted from 7398a92

0 commit comments

Comments
 (0)