Skip to content

Commit 57d0aea

Browse files
authored
Merge pull request #9 from mleegwt/master
Sensor fusion: Merge GPS fix and compass
2 parents e6a3d74 + becf429 commit 57d0aea

File tree

13 files changed

+251
-1
lines changed

13 files changed

+251
-1
lines changed

.github/workflows/action.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,16 @@ jobs:
1010
- uses: ros-tooling/setup-ros@v0.7
1111
with:
1212
required-ros-distributions: jazzy
13+
- uses: ros-tooling/action-ros-ci@v0.3
14+
with:
15+
package-name: boat_interfaces
16+
target-ros2-distro: jazzy
1317
- uses: ros-tooling/action-ros-ci@v0.3
1418
with:
1519
package-name: tempreader
1620
target-ros2-distro: jazzy
21+
- uses: ros-tooling/action-ros-ci@v0.3
22+
with:
23+
package-name: sensorfusion
24+
target-ros2-distro: jazzy
1725

README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,18 @@
1-
# karaburan
1+
# karaburan
2+
3+
Load ROS 2:
4+
`source /opt/ros/jazzy/setup.bash`
5+
6+
Build and run temperature sensor node (my SensorID):
7+
`colcon build && source ./install/setup.bash && ros2 run tempreader tempreaderNode --ros-args -p sensorId:=28.C23646D48524 &`
8+
9+
Launch GPSD client node:
10+
`ros2 launch gpsd_client gpsd_client-launch.py &`
11+
12+
Install ros-jazzy-gpsd-client
13+
14+
Read fixes from GPS:
15+
`ros2 topic echo /fix`
16+
17+
Read temperature:
18+
`ros2 topic echo /temperature`
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
cmake_minimum_required(VERSION 3.8)
2+
project(boat_interfaces)
3+
4+
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
5+
add_compile_options(-Wall -Wextra -Wpedantic)
6+
endif()
7+
8+
# find dependencies
9+
find_package(ament_cmake REQUIRED)
10+
find_package(rosidl_default_generators REQUIRED)
11+
# uncomment the following section in order to fill in
12+
# further dependencies manually.
13+
# find_package(<dependency> REQUIRED)
14+
15+
rosidl_generate_interfaces(${PROJECT_NAME}
16+
"msg/BoatHeading.msg"
17+
)
18+
19+
if(BUILD_TESTING)
20+
find_package(ament_lint_auto REQUIRED)
21+
# the following line skips the linter which checks for copyrights
22+
# comment the line when a copyright and license is added to all source files
23+
set(ament_cmake_copyright_FOUND TRUE)
24+
# the following line skips cpplint (only works in a git repo)
25+
# comment the line when this package is in a git repo and when
26+
# a copyright and license is added to all source files
27+
set(ament_cmake_cpplint_FOUND TRUE)
28+
ament_lint_auto_find_test_dependencies()
29+
endif()
30+
31+
ament_package()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uint32 heading
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0"?>
2+
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
3+
<package format="3">
4+
<name>boat_interfaces</name>
5+
<version>0.0.0</version>
6+
<description>TODO: Package description</description>
7+
<maintainer email="mleegwt@users.noreply.github.com">pi</maintainer>
8+
<license>TODO: License declaration</license>
9+
10+
<buildtool_depend>ament_cmake</buildtool_depend>
11+
12+
<buildtool_depend>rosidl_default_generators</buildtool_depend>
13+
<exec_depend>rosidl_default_runtime</exec_depend>
14+
<member_of_group>rosidl_interface_packages</member_of_group>
15+
16+
<!-- <test_depend>ament_lint_auto</test_depend>
17+
<test_depend>ament_lint_common</test_depend>-->
18+
19+
<export>
20+
<build_type>ament_cmake</build_type>
21+
</export>
22+
</package>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0"?>
2+
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
3+
<package format="3">
4+
<name>sensorfusion</name>
5+
<version>0.0.0</version>
6+
<description>TODO: Package description</description>
7+
<maintainer email="mleegwt@users.noreply.github.com">pi</maintainer>
8+
<license>TODO: License declaration</license>
9+
10+
<exec_depend>rclpy</exec_depend>
11+
<exec_depend>sensor_msgs</exec_depend>
12+
<exec_depend>std_msgs</exec_depend>
13+
<exec_depend>boat_interfaces</exec_depend>
14+
15+
<test_depend>ament_copyright</test_depend>
16+
<test_depend>ament_flake8</test_depend>
17+
<test_depend>ament_pep257</test_depend>
18+
<test_depend>python3-pytest</test_depend>
19+
20+
<export>
21+
<build_type>ament_python</build_type>
22+
</export>
23+
</package>

ros_ws/src/sensorfusion/resource/sensorfusion

Whitespace-only changes.

ros_ws/src/sensorfusion/sensorfusion/__init__.py

Whitespace-only changes.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import math
2+
3+
from boat_interfaces.msg import BoatHeading
4+
import rclpy
5+
from geometry_msgs.msg import PoseWithCovarianceStamped
6+
from geometry_msgs.msg import Quaternion
7+
from rclpy.node import Node
8+
from sensor_msgs.msg import NavSatFix
9+
10+
11+
def heading_to_quaternion(heading_deg):
12+
# Convert compass heading from degrees to radians
13+
heading_rad = math.radians(heading_deg)
14+
15+
# Calculate quaternion components
16+
qx = 0.0
17+
qy = 0.0
18+
qz = math.sin(heading_rad / 2)
19+
qw = math.cos(heading_rad / 2)
20+
21+
# Return quaternion
22+
return Quaternion(x=qx, y=qy, z=qz, w=qw)
23+
24+
25+
class SensorFusionNode(Node):
26+
27+
def __init__(self):
28+
super().__init__('sensor_fusion_node')
29+
self.gps_sub = self.create_subscription(NavSatFix, '/fix', self.gps_callback, 10)
30+
self.compass_sub = self.create_subscription(BoatHeading, '/compass', self.compass_callback, 10)
31+
self.pose_pub = self.create_publisher(PoseWithCovarianceStamped, '/amcl_pose', 10)
32+
self.current_lat = None
33+
self.current_lon = None
34+
self.current_heading = None # Heading from your custom compass
35+
36+
def gps_callback(self, msg):
37+
self.current_lat = msg.latitude
38+
self.current_lon = msg.longitude
39+
self.publish_pose()
40+
41+
def compass_callback(self, heading):
42+
self.current_heading = heading
43+
self.publish_pose()
44+
45+
def publish_pose(self):
46+
if self.current_lat is not None and self.current_lon is not None and self.current_heading is not None:
47+
pose_msg = PoseWithCovarianceStamped()
48+
pose_msg.header.stamp = self.get_clock().now().to_msg()
49+
pose_msg.header.frame_id = 'odom'
50+
51+
# Convert GPS to XY coordinates (this will need to be done with a transform library)
52+
# Simplified; typically requires a transform
53+
pose_msg.pose.pose.position.x = self.current_lon
54+
pose_msg.pose.pose.position.y = self.current_lat
55+
56+
# Convert compass heading to quaternion for orientation
57+
pose_msg.pose.pose.orientation = heading_to_quaternion(self.current_heading.heading)
58+
59+
self.pose_pub.publish(pose_msg)
60+
61+
62+
def main():
63+
rclpy.init()
64+
node = SensorFusionNode()
65+
rclpy.spin(node)
66+
node.destroy_node()
67+
rclpy.shutdown()
68+
69+
70+
if __name__ == '__main__':
71+
main()

ros_ws/src/sensorfusion/setup.cfg

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[develop]
2+
script_dir=$base/lib/sensorfusion
3+
[install]
4+
install_scripts=$base/lib/sensorfusion

0 commit comments

Comments
 (0)