Skip to content

Commit

Permalink
Merge pull request #91 from clearpathrobotics/humble-1.0RC
Browse files Browse the repository at this point in the history
Humble 1.0 RC
  • Loading branch information
tonybaltovski authored Nov 23, 2024
2 parents 78e0b38 + 7c66d0b commit f176c94
Show file tree
Hide file tree
Showing 6 changed files with 1,004 additions and 13 deletions.
132 changes: 120 additions & 12 deletions clearpath_config/manipulators/types/arms.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,19 @@ class BaseArm(BaseManipulator):
MANIPULATOR_MODEL = "base"
MANIPULATOR_TYPE = "arm"

IP_ADDRESS = "192.168.131.40"
IP_PORT = 10000
IP_ADDRESS = "ip"
IP_PORT = "port"
DEFAULT_IP_ADDRESS = "192.168.131.40"
DEFAULT_IP_PORT = 10000

URDF_PARAMETERS = {}

def __init__(
self,
idx: int = None,
name: str = None,
ip: str = IP_ADDRESS,
port: int = IP_PORT,
ip: str = DEFAULT_IP_ADDRESS,
port: int = DEFAULT_IP_PORT,
ros_parameters: dict = BaseManipulator.ROS_PARAMETERS,
ros_parameters_template: dict = BaseManipulator.ROS_PARAMETERS_TEMPLATE,
parent: str = Accessory.PARENT,
Expand All @@ -60,17 +64,19 @@ def __init__(
self.ip = IP(ip)
# IP Port
self.port = Port(port)
# URDF Parameters
self.urdf_parameters = dict(self.URDF_PARAMETERS)

@classmethod
def get_ip_from_idx(cls, idx: int) -> str:
ip = cls.IP_ADDRESS.split('.')
ip = cls.DEFAULT_IP_ADDRESS.split('.')
network_id = ip[0:3]
host_id = int(ip[-1]) + idx
return '.'.join(network_id) + '.' + str(host_id)

def set_idx(self, idx: int) -> None:
super().set_idx(idx)
if 'ip' not in self.config:
if self.IP_ADDRESS not in self.config:
self.ip = self.get_ip_from_idx(idx)
if self.gripper:
self.gripper.name = self.name + '_gripper'
Expand All @@ -94,12 +100,15 @@ def port(self, port: int) -> None:

def to_dict(self) -> dict:
d = super().to_dict()
d['ip'] = self.ip
d['port'] = self.port
d[self.IP_ADDRESS] = self.ip
d[self.IP_PORT] = self.port
if self.gripper:
d['gripper'] = self.gripper.to_dict()
else:
d['gripper'] = None
for k, v in self.urdf_parameters.items():
if v:
d[k] = v
return d

def from_dict(self, d: dict) -> None:
Expand All @@ -111,10 +120,20 @@ def from_dict(self, d: dict) -> None:
self.gripper.set_name('%s_gripper' % self.get_name())
if 'parent' not in d['gripper']:
self.gripper.set_parent('%s_end_effector_link' % self.get_name())
if 'ip' in d:
self.ip = d['ip']
if 'port' in d:
self.port = d['port']
if self.IP_ADDRESS in d:
self.ip = d[self.IP_ADDRESS]
if self.IP_PORT in d:
self.port = d[self.IP_PORT]
for k in self.urdf_parameters:
if k in d:
self.urdf_parameters[k] = d[k]

def get_urdf_parameters(self) -> dict:
d = {}
for k, v in self.urdf_parameters.items():
if v:
d[k] = v
return d


class KinovaGen3Dof6(BaseArm):
Expand All @@ -129,15 +148,104 @@ class KinovaGen3Lite(BaseArm):
MANIPULATOR_MODEL = "kinova_gen3_lite"


class UniversalRobots(BaseArm):
MANIPULATOR_MODEL = "universal_robots"

# Description Variables
UR_TYPE = 'ur_type'
INITIAL_POSITIONS = 'initial_positions'
INITIAL_POSITIONS_FILE = 'initial_positions_file'
JOINT_LIMITS_PARAMETERS_FILE = 'joint_limits_parameters_file'
KINEMATICS_PARAMETERS_FILE = 'kinematics_parameters_file'
PHYSICAL_PARAMETERS_FILE = 'physical_parameters_file'
VISUAL_PARAMETERS_FILE = 'visual_parameters_file'
SAFETY_LIMITS = 'safety_limits'
SAFETY_POS_MARGIN = 'safety_pos_margin'
SAFETY_K_POSITION = 'safety_k_position'
# Control Parameters
GENERATE_ROS2_CONTROL_TAG = 'generate_ros2_control_tag'
HEADLESS_MODE = 'headless_mode'
IP_ADDRESS = 'robot_ip'
SCRIPT_FILENAME = 'script_filename'
OUTPUT_RECIPE_FILENAME = 'output_recipe_filename'
INPUT_RECIPE_FILENAME = 'input_recipe_filename'
REVERSE_IP = 'reverse_ip'
SCRIPT_COMMAND_PORT = 'script_command_port'
REVERSE_PORT = 'reverse_port'
SCRIPT_SENDER_PORT = 'script_sender_port'
TRAJECTORY_PORT = 'trajectory_port'
TRANSMISSION_HW_INTERFACE = 'transmission_hw_interface'
NON_BLOCKING_READ = 'non_blocking_read'
KEEP_ALIVE_COUNT = 'keep_alive_count'
# Tool Communication Parameters
USE_TOOL_COMMUNICATION = 'use_tool_communication'
TOOL_VOLTAGE = 'tool_voltage'
TOOL_PARITY = 'tool_parity'
TOOL_BAUD_RATE = 'tool_baud_rate'
TOOL_STOP_BITS = 'tool_stop_bits'
TOOL_RX_IDLE_CHARS = 'tool_rx_idle_chars'
TOOL_TX_IDLE_CHARS = 'tool_tx_idle_chars'
TOOL_DEVICE_NAME = 'tool_device_name'
TOOL_TCP_PORT = 'tool_tcp_port'
# Simulation Parameters
USE_FAKE_HARDWARE = 'use_fake_hardware'
FAKE_SENSOR_COMMANDS = 'fake_sensor_commands'
SIM_GAZEBO = 'sim_gazebo'
SIM_IGNITION = 'sim_ignition'

# URDF Parameters
URDF_PARAMETERS = {
UR_TYPE: '',
INITIAL_POSITIONS: '',
INITIAL_POSITIONS_FILE: '',
JOINT_LIMITS_PARAMETERS_FILE: '',
KINEMATICS_PARAMETERS_FILE: '',
PHYSICAL_PARAMETERS_FILE: '',
VISUAL_PARAMETERS_FILE: '',
SAFETY_LIMITS: '',
SAFETY_POS_MARGIN: '',
SAFETY_K_POSITION: '',
GENERATE_ROS2_CONTROL_TAG: '',
HEADLESS_MODE: '',
IP_ADDRESS: '',
SCRIPT_FILENAME: '',
OUTPUT_RECIPE_FILENAME: '',
INPUT_RECIPE_FILENAME: '',
REVERSE_IP: '',
SCRIPT_COMMAND_PORT: '',
REVERSE_PORT: '',
SCRIPT_SENDER_PORT: '',
TRAJECTORY_PORT: '',
TRANSMISSION_HW_INTERFACE: '',
NON_BLOCKING_READ: '',
KEEP_ALIVE_COUNT: '',
USE_TOOL_COMMUNICATION: '',
TOOL_VOLTAGE: '',
TOOL_PARITY: '',
TOOL_BAUD_RATE: '',
TOOL_STOP_BITS: '',
TOOL_RX_IDLE_CHARS: '',
TOOL_TX_IDLE_CHARS: '',
TOOL_DEVICE_NAME: '',
TOOL_TCP_PORT: '',
USE_FAKE_HARDWARE: '',
FAKE_SENSOR_COMMANDS: '',
SIM_GAZEBO: '',
SIM_IGNITION: '',
}


class Arm():
KINOVA_GEN3_6DOF = KinovaGen3Dof6.MANIPULATOR_MODEL
KINOVA_GEN3_7DOF = KinovaGen3Dof7.MANIPULATOR_MODEL
KINOVA_GEN3_LITE = KinovaGen3Lite.MANIPULATOR_MODEL
UNIVERSAL_ROBOTS = UniversalRobots.MANIPULATOR_MODEL

MODEL = {
KINOVA_GEN3_6DOF: KinovaGen3Dof6,
KINOVA_GEN3_7DOF: KinovaGen3Dof7,
KINOVA_GEN3_LITE: KinovaGen3Lite,
UNIVERSAL_ROBOTS: UniversalRobots,
}

@classmethod
Expand Down
187 changes: 187 additions & 0 deletions clearpath_config/platform/can.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# Software License Agreement (BSD)
#
# @author Luis Camero <[email protected]>
# @copyright (c) 2024, Clearpath Robotics, Inc., All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Clearpath Robotics nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from clearpath_config.common.types.config import BaseConfig
from clearpath_config.common.types.list import ListConfig
from clearpath_config.common.types.platform import Platform
from typing import List


class CANBridge:
INTERFACE = "interface"
ENABLE_CAN_FD = "enable_can_fd"
INTERVAL = "interval"
USE_BUS_TIME = "use_bus_time"
FILTERS = "filters"
AUTO_CONFIGURE = "auto_configure"
AUTO_ACTIVATE = "auto_activate"
TOPIC_RX = "topic_rx"
TOPIC_TX = "topic_tx"

DEFAULTS = {
INTERFACE: "can0",
ENABLE_CAN_FD: False,
INTERVAL: 0.01,
USE_BUS_TIME: False,
FILTERS: "0:0",
AUTO_CONFIGURE: True,
AUTO_ACTIVATE: True,
TOPIC_RX: "can0/rx",
TOPIC_TX: "can0/tx"
}

def __init__(
self,
interface: str = DEFAULTS[INTERFACE],
enable_can_fd: bool = DEFAULTS[ENABLE_CAN_FD],
interval: float = DEFAULTS[INTERVAL],
use_bus_time: bool = DEFAULTS[USE_BUS_TIME],
filters: str = DEFAULTS[FILTERS],
auto_configure: bool = DEFAULTS[AUTO_CONFIGURE],
auto_activate: bool = DEFAULTS[AUTO_ACTIVATE],
topic_rx: str = DEFAULTS[TOPIC_RX],
topic_tx: str = DEFAULTS[TOPIC_TX],
) -> None:
self.topic_rx = topic_rx
self.topic_tx = topic_tx
self.interface = interface
self.enaled_can_fd = enable_can_fd
self.interval = interval
self.use_bus_time = use_bus_time
self.filters = filters
self.auto_configure = auto_configure
self.auto_activate = auto_activate

def to_dict(self) -> dict:
d = dict()
d[self.INTERFACE] = self.interface
d[self.ENABLE_CAN_FD] = self.enaled_can_fd
d[self.INTERVAL] = self.interval
d[self.USE_BUS_TIME] = self.use_bus_time
d[self.FILTERS] = self.filters
d[self.AUTO_CONFIGURE] = self.auto_configure
d[self.AUTO_ACTIVATE] = self.auto_activate
d[self.TOPIC_RX] = self.topic_rx
d[self.TOPIC_TX] = self.topic_tx
return d

def from_dict(self, d: dict) -> None:
if self.INTERFACE in d:
self.interface = d[self.INTERFACE]
if self.ENABLE_CAN_FD in d:
self.enaled_can_fd = d[self.ENABLE_CAN_FD]
if self.INTERVAL in d:
self.interval = d[self.INTERVAL]
if self.USE_BUS_TIME in d:
self.use_bus_time = d[self.USE_BUS_TIME]
if self.FILTERS in d:
self.filters = d[self.FILTERS]
if self.AUTO_CONFIGURE in d:
self.auto_configure = d[self.AUTO_CONFIGURE]
if self.AUTO_ACTIVATE in d:
self.auto_activate = d[self.AUTO_ACTIVATE]
if self.TOPIC_RX in d:
self.topic_rx = d[self.TOPIC_RX]
if self.TOPIC_TX in d:
self.topic_tx = d[self.TOPIC_TX]

@property
def interface(self) -> str:
return self._interface

@interface.setter
def interface(self, interface: str) -> None:
self._interface = interface
if self.topic_rx == self.DEFAULTS[self.TOPIC_RX]:
self.topic_rx = f"{interface}/rx"
if self.topic_tx == self.DEFAULTS[self.TOPIC_TX]:
self.topic_tx = f"{interface}/tx"


class CANBridgeListConfig(ListConfig[CANBridge, str]):
def __init__(self) -> None:
super().__init__(
uid=lambda obj: obj.interface,
obj_type=CANBridge,
uid_type=str
)


class CANBridgeConfig:
SINGLE_VCAN_DEFAULT = [
{
CANBridge.INTERFACE: "vcan0",
CANBridge.ENABLE_CAN_FD: False,
CANBridge.INTERVAL: 0.01,
CANBridge.USE_BUS_TIME: False,
CANBridge.FILTERS: "0:0",
CANBridge.AUTO_CONFIGURE: True,
CANBridge.AUTO_ACTIVATE: True,
}
]

DEFAULTS = {
Platform.A200: [],
Platform.DD100: SINGLE_VCAN_DEFAULT,
Platform.DD150: SINGLE_VCAN_DEFAULT,
Platform.DO100: SINGLE_VCAN_DEFAULT,
Platform.DO150: SINGLE_VCAN_DEFAULT,
Platform.GENERIC: [],
Platform.J100: [],
Platform.R100: SINGLE_VCAN_DEFAULT,
Platform.W200: [],
}

def __init__(
self,
config: dict = {}
) -> None:
self._can_bridges = CANBridgeListConfig()
self.config = config

def __add__(self, other):
self._can_bridges.extend(other.get_all())
return self

def get_all(self) -> List[CANBridge]:
return self._can_bridges.get_all()

@property
def config(self):
return [a.to_dict() for a in self.get_all()]

@config.setter
def config(self, can_bridges: list):
self._can_bridges.remove_all()
for b in can_bridges:
bridge = CANBridge()
bridge.from_dict(b)
self._can_bridges.add(bridge)

def update(self, serial_number: bool = False) -> None:
if serial_number:
self.config = self.DEFAULTS[BaseConfig.get_platform_model()]
Loading

0 comments on commit f176c94

Please sign in to comment.