Skip to content

Commit e9173d6

Browse files
committed
Feat: first draw of the driver
0 parents  commit e9173d6

File tree

8 files changed

+115
-0
lines changed

8 files changed

+115
-0
lines changed

package.xml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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>ros2_lx16a_driver</name>
5+
<version>0.0.0</version>
6+
<description>Package ROS2 for controlling LewanSoul LX-16A servos</description>
7+
<maintainer email="[email protected]">florisjousselin</maintainer>
8+
<license>BSD3</license>
9+
10+
<buildtool_depend>ament_cmake</buildtool_depend>
11+
<exec_depend>rclpy</exec_depend>
12+
<exec_depend>serial</exec_depend>
13+
14+
<export>
15+
<build_type>ament_python</build_type>
16+
</export>
17+
</package>

resource/ros2_lx16a_driver

Whitespace-only changes.

ros2_lx16a_driver/__init__.py

Whitespace-only changes.

ros2_lx16a_driver/lx16a_driver.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import serial
2+
import struct
3+
4+
class LX16ADriver:
5+
def __init__(self, port, baudrate=115200):
6+
self.ser = serial.Serial(port, baudrate, timeout=1)
7+
8+
def send_command(self, servo_id, command, params):
9+
length = 3 + len(params)
10+
packet = [0x55, 0x55, servo_id, length, command] + params
11+
checksum = ~sum(packet[2:]) & 0xFF
12+
packet.append(checksum)
13+
self.ser.write(bytearray(packet))
14+
15+
def move(self, servo_id, position):
16+
pos = int(position * 1000 / 240)
17+
params = list(struct.pack('<H', pos))
18+
self.send_command(servo_id, 1, params)
19+
20+
def get_physical_angle(self, servo_id):
21+
self.send_command(servo_id, 28, [])
22+
response = self.ser.read(7)
23+
if len(response) == 7:
24+
angle = struct.unpack('<H', response[5:7])[0]
25+
return angle * 240 / 1000
26+
return None
27+
28+
def close(self):
29+
self.ser.close()

ros2_lx16a_driver/lx16a_node.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import rclpy
2+
from rclpy.node import Node
3+
from std_msgs.msg import Float64
4+
from .lx16a_driver import LX16ADriver
5+
6+
class LX16ANode(Node):
7+
def __init__(self):
8+
super().__init__('lx16a_node')
9+
self.driver = LX16ADriver('/dev/ttyUSB0') # Adapter au port série correct
10+
self.subscription = self.create_subscription(
11+
Float64,
12+
'servo_angle',
13+
self.set_servo_angle,
14+
10
15+
)
16+
self.get_logger().info('LX16A Node started')
17+
18+
def set_servo_angle(self, msg):
19+
angle = msg.data
20+
self.get_logger().info(f'Setting servo to {angle} degrees')
21+
self.driver.move(1, angle)
22+
23+
def destroy_node(self):
24+
self.driver.close()
25+
super().destroy_node()
26+
27+
def main(args=None):
28+
rclpy.init(args=args)
29+
node = LX16ANode()
30+
rclpy.spin(node)
31+
node.destroy_node()
32+
rclpy.shutdown()

setup.cfg

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[develop]
2+
script_dir=$base/lib/ros2_lx16a_driver
3+
[install]
4+
install_scripts=$base/lib/ros2_lx16a_driver

setup.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from setuptools import setup
2+
3+
package_name = 'ros2_lx16a_driver'
4+
5+
setup(
6+
name=package_name,
7+
version='0.0.0',
8+
packages=[package_name],
9+
data_files=[
10+
('share/ament_index/resource_index/packages', ['resource/' + package_name]),
11+
('share/' + package_name, ['package.xml']),
12+
],
13+
install_requires=['setuptools'],
14+
zip_safe=True,
15+
maintainer='florisjousselin',
16+
maintainer_email='[email protected]',
17+
description='Package ROS2 for controlling LewanSoul LX-16A servos',
18+
license='BSD3',
19+
tests_require=['pytest'],
20+
entry_points={
21+
'console_scripts': [
22+
'lx16a_node = ros2_lx16a_driver.lx16a_node:main',
23+
],
24+
},
25+
)

test/test_lx16a.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import unittest
2+
from ros2_lx16a.lx16a_driver import LX16ADriver
3+
4+
class TestLX16ADriver(unittest.TestCase):
5+
def test_move(self):
6+
driver = LX16ADriver('/dev/null')
7+
driver.move(1, 90)
8+
self.assertTrue(True)

0 commit comments

Comments
 (0)