Skip to content

Commit 3cb05ed

Browse files
authored
Merge pull request #10 from mleegwt/master
Initial untested version of boatcontrol node.
2 parents 57d0aea + 238cbf3 commit 3cb05ed

File tree

16 files changed

+413
-9
lines changed

16 files changed

+413
-9
lines changed

.github/workflows/action.yml

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,6 @@ jobs:
1212
required-ros-distributions: jazzy
1313
- uses: ros-tooling/action-ros-ci@v0.3
1414
with:
15-
package-name: boat_interfaces
16-
target-ros2-distro: jazzy
17-
- uses: ros-tooling/action-ros-ci@v0.3
18-
with:
19-
package-name: tempreader
20-
target-ros2-distro: jazzy
21-
- uses: ros-tooling/action-ros-ci@v0.3
22-
with:
23-
package-name: sensorfusion
15+
package-name: boat_interfaces boatcontrol navigation tempreader sensorfusion
2416
target-ros2-distro: jazzy
2517

ros_ws/src/boatcontrol/boatcontrol/__init__.py

Whitespace-only changes.
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#python 3
2+
import serial
3+
import time
4+
import math
5+
import rclpy
6+
from rclpy.node import Node
7+
8+
# Initialize serial communication for actuator control
9+
serial_port = "/dev/ttyUSB0" # Update with your port
10+
baud_rate = 115200 # Adjust baud rate as per your actuator settings
11+
ser = serial.Serial(serial_port, baud_rate, timeout=1)
12+
13+
def send_command(command):
14+
if ser.is_open:
15+
ser.write(command.encode())
16+
time.sleep(1)
17+
response=""
18+
while "OK" not in response:
19+
response = ser.readline().decode().strip() # Read response from the actuator
20+
#print(f"got:{response}")
21+
time.sleep(0.2)
22+
print(f"Sent: {command}, Received: {response}")
23+
return response
24+
25+
# Function to send enable motor command
26+
def send_calib_command():
27+
send_command(f"POST CALIB")
28+
29+
# Function to send enable motor command
30+
def send_enable_command():
31+
send_command(f"POST WD 30") #enable motor for 30s
32+
33+
# Function to send command to the actuator
34+
def send_move_command(command):
35+
send_command(f"POST MOVE {command}")
36+
37+
def send_nav_command(duration, heading):
38+
send_command(f"POST NAV {duration} {heading}")
39+
40+
def send_speed_command(speed):
41+
send_command(f"POST SPEED {speed}")
42+
43+
# Function to send command to the actuator
44+
def get_heading_command():
45+
response = send_command(f"GET HEADING")
46+
47+
# Parse the heading from the response
48+
try:
49+
# Find the start and end of the heading value within the response string
50+
start = response.index("heading:") + len("heading:")
51+
end = response.index("}", start)
52+
heading_value = float(response[start:end].strip()) # Convert to float
53+
return heading_value
54+
except (ValueError, IndexError) as e:
55+
print(f"Error parsing heading: {e}")
56+
return None
57+
58+
59+
class BoatControlNode(Node):
60+
61+
def __init__(self):
62+
super().__init__('boat_control_node')
63+
self.compass_pub = self.create_publisher(BoatHeading, '/compass', 10)
64+
self.heading_sub = self.create_subscriber(Float64, '/desired_heading', self.heading_callback, 10)
65+
self.speed_sub = self.create_subscriber(Float64, '/desired_speed', self.speed_callback, 10)
66+
self.current_heading = None
67+
timer_period = 1 # Seconds
68+
self.timer = self.create_timer(timer_period, self.timer_callback)
69+
70+
def timer_callback(self):
71+
send_enable_command()
72+
current_heading = get_heading_command()
73+
current_heading = get_heading_command()# dual reading to flush !
74+
75+
msg = BoatHeading()
76+
msg.heading = current_heading
77+
self.compass_pub.publish(msg)
78+
79+
def heading_callback(self, heading):
80+
send_nav_command(10, heading)
81+
82+
def speed_callback(self, speed):
83+
send_speed_command(speed)
84+
85+
def main():
86+
rclpy.init()
87+
node = BoatControlNode()
88+
rclpy.spin(node)
89+
node.destroy_node()
90+
rclpy.shutdown()
91+
92+
93+
if __name__ == '__main__':
94+
try:
95+
time.sleep(0.5)
96+
response = ser.readline().decode().strip() # Read response from the actuator
97+
print(f"Received: {response}")
98+
response = ser.readline().decode().strip() # Read response from the actuator
99+
print(f"Received: {response}")
100+
send_enable_command()
101+
time.sleep(1)
102+
send_calib_command()
103+
send_speed_command(30)
104+
main()
105+
except KeyboardInterrupt:
106+
print("Control loop interrupted. Exiting...")
107+
finally:
108+
if ser.is_open:
109+
ser.close()

ros_ws/src/boatcontrol/package.xml

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>boatcontrol</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+
<depend>math</depend>
11+
<depend>rclpy</depend>
12+
<depend>serial</depend>
13+
<depend>time</depend>
14+
15+
<test_depend>ament_copyright</test_depend>
16+
<test_depend>ament_pep257</test_depend>
17+
<test_depend>python3-pytest</test_depend>
18+
19+
<export>
20+
<build_type>ament_python</build_type>
21+
</export>
22+
</package>

ros_ws/src/boatcontrol/resource/boatcontrol

Whitespace-only changes.

ros_ws/src/boatcontrol/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/boatcontrol
3+
[install]
4+
install_scripts=$base/lib/boatcontrol

ros_ws/src/boatcontrol/setup.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from setuptools import find_packages, setup
2+
3+
package_name = 'boatcontrol'
4+
5+
setup(
6+
name=package_name,
7+
version='0.0.0',
8+
packages=find_packages(exclude=['test']),
9+
data_files=[
10+
('share/ament_index/resource_index/packages',
11+
['resource/' + package_name]),
12+
('share/' + package_name, ['package.xml']),
13+
],
14+
install_requires=['setuptools'],
15+
zip_safe=True,
16+
maintainer='pi',
17+
maintainer_email='mleegwt@users.noreply.github.com',
18+
description='TODO: Package description',
19+
license='TODO: License declaration',
20+
tests_require=['pytest'],
21+
entry_points={
22+
'console_scripts': [
23+
],
24+
},
25+
)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright 2015 Open Source Robotics Foundation, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from ament_copyright.main import main
16+
import pytest
17+
18+
19+
# Remove the `skip` decorator once the source file(s) have a copyright header
20+
@pytest.mark.skip(reason='No copyright header has been placed in the generated source file.')
21+
@pytest.mark.copyright
22+
@pytest.mark.linter
23+
def test_copyright():
24+
rc = main(argv=['.', 'test'])
25+
assert rc == 0, 'Found errors'
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright 2015 Open Source Robotics Foundation, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from ament_pep257.main import main
16+
import pytest
17+
18+
19+
@pytest.mark.linter
20+
@pytest.mark.pep257
21+
def test_pep257():
22+
rc = main(argv=['.', 'test'])
23+
assert rc == 0, 'Found code style errors / warnings'

ros_ws/src/navigation/navigation/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)