Compare commits
41 Commits
async_traj
...
5591cdabc9
| Author | SHA1 | Date | |
|---|---|---|---|
| 5591cdabc9 | |||
| 7ce34b4834 | |||
| 9e191df7e4 | |||
| edcdcb9131 | |||
| 47360764ea | |||
| 2238952f34 | |||
| 55be0910d5 | |||
| d3e533fdde | |||
| 45a3a3ac4d | |||
| bdcccdc06e | |||
| cdef55b647 | |||
| c421ef4482 | |||
| 5145ffa6ac | |||
| 7f547c65f7 | |||
| 925a9b42c7 | |||
| 5a00d7b258 | |||
| 28bf1413c2 | |||
| 2372404732 | |||
| d58b968536 | |||
| 931ffe54b7 | |||
| 93e5707ca9 | |||
| fde362b526 | |||
| 0c2aff9fbd | |||
| ef6d4a27be | |||
| cb1923e56a | |||
| a9ab26aeed | |||
| 6910d06c2e | |||
| 360528808e | |||
| ba13618c95 | |||
| dc0445abca | |||
| 6c45716832 | |||
| 9e9ec2d3f9 | |||
| 6467d80bc0 | |||
| 1c02d8dce2 | |||
| 6d6f2aa393 | |||
| c5761dc8e8 | |||
| e771acd598 | |||
| 2aee36b333 | |||
| 1d11b96b49 | |||
| ef994440f4 | |||
| 2e28c4e99f |
@@ -12,6 +12,8 @@ ENV WS_INSTALL_DIR=${WS_DIR}/install
|
|||||||
ENV WS_LOG_DIR=${WS_DIR}/log
|
ENV WS_LOG_DIR=${WS_DIR}/log
|
||||||
WORKDIR ${WS_DIR}
|
WORKDIR ${WS_DIR}
|
||||||
|
|
||||||
|
COPY config.yaml ${WS_DIR}/
|
||||||
|
|
||||||
### Install Gazebo
|
### Install Gazebo
|
||||||
ARG IGNITION_VERSION=fortress
|
ARG IGNITION_VERSION=fortress
|
||||||
ENV IGNITION_VERSION=${IGNITION_VERSION}
|
ENV IGNITION_VERSION=${IGNITION_VERSION}
|
||||||
@@ -25,6 +27,9 @@ RUN apt-get update && \
|
|||||||
apt-get install -yq python3-pil.imagetk && \
|
apt-get install -yq python3-pil.imagetk && \
|
||||||
apt-get install -yq ros-${ROS_DISTRO}-pilz-industrial-motion-planner && \
|
apt-get install -yq ros-${ROS_DISTRO}-pilz-industrial-motion-planner && \
|
||||||
apt-get install -yq tmux && \
|
apt-get install -yq tmux && \
|
||||||
|
apt-get install -yq nano && \
|
||||||
|
apt-get install -yq vim && \
|
||||||
|
apt-get install -yq less && \
|
||||||
apt-get install -yq python3-pip && \
|
apt-get install -yq python3-pip && \
|
||||||
apt-get install -yq ros-${ROS_DISTRO}-desktop && \
|
apt-get install -yq ros-${ROS_DISTRO}-desktop && \
|
||||||
apt-get install -yq ros-${ROS_DISTRO}-rclcpp-components
|
apt-get install -yq ros-${ROS_DISTRO}-rclcpp-components
|
||||||
@@ -75,7 +80,7 @@ RUN source "/opt/ros/${ROS_DISTRO}/setup.bash" && \
|
|||||||
rm -rf ${WS_LOG_DIR}
|
rm -rf ${WS_LOG_DIR}
|
||||||
|
|
||||||
# Copy example svg images
|
# Copy example svg images
|
||||||
COPY ./svg svg
|
COPY ./svg test-images
|
||||||
|
|
||||||
### Add workspace to the ROS entrypoint
|
### Add workspace to the ROS entrypoint
|
||||||
### Source ROS workspace inside `~/.bashrc` to enable autocompletion
|
### Source ROS workspace inside `~/.bashrc` to enable autocompletion
|
||||||
|
|||||||
62
README.md
62
README.md
@@ -35,6 +35,23 @@ bash .docker/devel.bash
|
|||||||
```
|
```
|
||||||
This will mount the host `drawing-robot-ros2` directory in the container at `src/drawing-robot-ros2`.
|
This will mount the host `drawing-robot-ros2` directory in the container at `src/drawing-robot-ros2`.
|
||||||
|
|
||||||
|
Optionally you can pass a directory to the container with
|
||||||
|
``` sh
|
||||||
|
bash .docker/run.bash -v PATH_TO_SVG:/svg:rw
|
||||||
|
```
|
||||||
|
This will mount the given path to /svg in read-write mode in the container.
|
||||||
|
|
||||||
|
|
||||||
|
#### Podman issues
|
||||||
|
If using podman instead of docker, using the following will allow the container to access `/dev/` which is needed by the axidraw robot.
|
||||||
|
``` sh
|
||||||
|
sudo bash .docker/build.bash
|
||||||
|
```
|
||||||
|
``` sh
|
||||||
|
sudo bash .docker/devel.bash
|
||||||
|
```
|
||||||
|
Adding sudo may cause gazebo not to work, so it is recommended to use docker instead of podman.
|
||||||
|
|
||||||
## TODO Building locally
|
## TODO Building locally
|
||||||
|
|
||||||
Requirements:
|
Requirements:
|
||||||
@@ -60,26 +77,42 @@ DummyController echoes Motion messages to the terminal.
|
|||||||
ros2 run robot_controller dummy_controller
|
ros2 run robot_controller dummy_controller
|
||||||
```
|
```
|
||||||
|
|
||||||
AxidrawController draws on the axidraw robot
|
### AxidrawController
|
||||||
|
AxidrawController draws on the axidraw robot.
|
||||||
|
Find the serial device in "/dev/", it is usually named "/dev/ttyACMX" where X is usually 0.
|
||||||
|
Try a different serial port if the axidraw_controller continuously logs a message about failing to connect.
|
||||||
``` sh
|
``` sh
|
||||||
ros2 launch axidraw_controller axidraw_controller
|
ros2 launch axidraw_controller axidraw_controller.launch.py serial_port:=/dev/ttyACM0 config:=./config.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Lite6Controller
|
||||||
This starts the simulated lite6
|
This starts the simulated lite6
|
||||||
``` sh
|
``` sh
|
||||||
ros2 launch lite6_controller lite6_gazebo.launch.py
|
ros2 launch lite6_controller lite6_gazebo.launch.py config:=./config.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
This runs the real lite6
|
This runs the real lite6
|
||||||
``` sh
|
``` sh
|
||||||
ros2 launch lite6_controller lite6_real.launch.py
|
ros2 launch lite6_controller lite6_real.launch.py config:=./config.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
This runs the real lite6 without Rviz (can be run on headless device over ssh)
|
This runs the real lite6 without Rviz (can be run on headless device over ssh)
|
||||||
``` sh
|
``` sh
|
||||||
ros2 launch lite6_controller lite6_real_no_gui.launch.py
|
ros2 launch lite6_controller lite6_real_no_gui.launch.py config:=./config.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Before using the real lite6, it is recommended to run the calibration program.
|
||||||
|
A lite6_controller must be running for calibration.
|
||||||
|
This can be used to measure the Z height for a specific pen.
|
||||||
|
The program also moves the arm to a known default position.
|
||||||
|
``` sh
|
||||||
|
ros2 run lite6_controller lite6_calibration
|
||||||
|
```
|
||||||
|
Follow the instructions, pressing enter when prompted.
|
||||||
|
|
||||||
|
Change the Z-offset value accordingly.
|
||||||
|
Restart the running lite6_controller after calibration.
|
||||||
|
|
||||||
### DrawingController
|
### DrawingController
|
||||||
Once a RobotController is running, simultaneously (using tmux or another terminal) run
|
Once a RobotController is running, simultaneously (using tmux or another terminal) run
|
||||||
``` sh
|
``` sh
|
||||||
@@ -87,6 +120,23 @@ ros2 run drawing_controller drawing_controller svg/test.svg
|
|||||||
```
|
```
|
||||||
This will draw the svg image given as the last argument.
|
This will draw the svg image given as the last argument.
|
||||||
|
|
||||||
|
### tmux workflow
|
||||||
|
lite6 interface: http://192.168.1.150:18333
|
||||||
|
|
||||||
|
#### Raspberry pi
|
||||||
|
On the raspberry pi run
|
||||||
|
``` sh
|
||||||
|
./setup_ros.sh
|
||||||
|
```
|
||||||
|
This will open a tmux session with the necessary ros2 packages sourced.
|
||||||
|
#### Docker container
|
||||||
|
``` sh
|
||||||
|
tmux
|
||||||
|
```
|
||||||
|
|
||||||
|
If actively
|
||||||
|
|
||||||
|
|
||||||
## SVG compatibility info
|
## SVG compatibility info
|
||||||
Tested with SVG from the following programs
|
Tested with SVG from the following programs
|
||||||
- Inkscape
|
- Inkscape
|
||||||
@@ -177,7 +227,7 @@ And the following SVG path commands are supported:
|
|||||||
| MoveTo | M, m | |
|
| MoveTo | M, m | |
|
||||||
| LineTo | L, l, H, h, V, v | |
|
| LineTo | L, l, H, h, V, v | |
|
||||||
| Cubic Bézier Curve | C, c, S, s | |
|
| Cubic Bézier Curve | C, c, S, s | |
|
||||||
| Quadratic Bézier Curve | | Q, q, T, t |
|
| Quadratic Bézier Curve | Q, q | T, t |
|
||||||
| Elliptical Arc Curve | | A, a |
|
| Elliptical Arc Curve | | A, a |
|
||||||
| ClosePath | Z, z | |
|
| ClosePath | Z, z | |
|
||||||
|
|
||||||
|
|||||||
26
config.yaml
Normal file
26
config.yaml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/robot_controller:
|
||||||
|
ros__parameters:
|
||||||
|
lite6_x_limit_lower: 0.1
|
||||||
|
lite6_x_limit_upper: 0.305
|
||||||
|
lite6_y_limit_lower: -0.1475
|
||||||
|
lite6_y_limit_upper: 0.1475
|
||||||
|
|
||||||
|
lite6_z_lift_amount: 0.01
|
||||||
|
lite6_z_offset: 0.201942
|
||||||
|
|
||||||
|
lite6_blend_radius: 0.0
|
||||||
|
lite6_max_velocity_scaling_factor: 1.0
|
||||||
|
lite6_max_acceleration_scaling_factor: 0.9
|
||||||
|
|
||||||
|
/axidraw_serial:
|
||||||
|
ros__parameters:
|
||||||
|
axidraw_accel: 100
|
||||||
|
axidraw_speed_pendown: 50
|
||||||
|
axidraw_speed_penup: 50
|
||||||
|
axidraw_const_speed: false
|
||||||
|
axidraw_pen_delay_down: 0
|
||||||
|
axidraw_pen_delay_up: 0
|
||||||
|
axidraw_pen_pos_down: 40
|
||||||
|
axidraw_pen_pos_up: 60
|
||||||
|
axidraw_pen_rate_lower: 50
|
||||||
|
axidraw_pen_rate_raise: 75
|
||||||
12
scripts/log_drawing.sh
Executable file
12
scripts/log_drawing.sh
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# Logs drawn images
|
||||||
|
# ./log_drawing.sh ROBOTNAME SVG
|
||||||
|
# ROBOTNAME: robot name (logged before output)
|
||||||
|
# SVG: svg path to be drawn
|
||||||
|
|
||||||
|
date >> data.txt
|
||||||
|
echo $1 >> data.txt
|
||||||
|
ros2 run drawing_controller drawing_controller $2 2>&1 | grep 'Results' | tee -a data.txt
|
||||||
|
echo '\n' >> data.txt
|
||||||
|
|
||||||
|
#{'svg processing time': '00:00:02', 'failure': 65, 'total time': '00:00:09', 'drawing time': '00:00:06'}
|
||||||
@@ -40,6 +40,11 @@ install(PROGRAMS
|
|||||||
DESTINATION lib/${PROJECT_NAME}
|
DESTINATION lib/${PROJECT_NAME}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
install(DIRECTORY
|
||||||
|
config
|
||||||
|
DESTINATION share/${PROJECT_NAME}
|
||||||
|
)
|
||||||
|
|
||||||
if(BUILD_TESTING)
|
if(BUILD_TESTING)
|
||||||
find_package(ament_lint_auto REQUIRED)
|
find_package(ament_lint_auto REQUIRED)
|
||||||
# the following line skips the linter which checks for copyrights
|
# the following line skips the linter which checks for copyrights
|
||||||
|
|||||||
12
src/axidraw_controller/config/config.yaml
Normal file
12
src/axidraw_controller/config/config.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/axidraw_serial:
|
||||||
|
ros__parameters:
|
||||||
|
axidraw_accel: 100
|
||||||
|
axidraw_const_speed: false
|
||||||
|
axidraw_pen_delay_down: 0
|
||||||
|
axidraw_pen_delay_up: 0
|
||||||
|
axidraw_pen_pos_down: 40
|
||||||
|
axidraw_pen_pos_up: 60
|
||||||
|
axidraw_pen_rate_lower: 50
|
||||||
|
axidraw_pen_rate_raise: 75
|
||||||
|
axidraw_speed_pendown: 50
|
||||||
|
axidraw_speed_penup: 50
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
import yaml
|
||||||
from launch import LaunchDescription
|
from launch import LaunchDescription
|
||||||
from launch.actions import OpaqueFunction, IncludeLaunchDescription, DeclareLaunchArgument
|
from launch.actions import OpaqueFunction, IncludeLaunchDescription, DeclareLaunchArgument
|
||||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
||||||
@@ -18,6 +19,13 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
serial_port = LaunchConfiguration('serial_port', default='/dev/ttyACM0')
|
serial_port = LaunchConfiguration('serial_port', default='/dev/ttyACM0')
|
||||||
log_level = LaunchConfiguration("log_level", default='info')
|
log_level = LaunchConfiguration("log_level", default='info')
|
||||||
|
|
||||||
|
config = LaunchConfiguration("config", default=PathJoinSubstitution([FindPackageShare('axidraw_controller'), 'config', 'config.yaml']))
|
||||||
|
|
||||||
|
robotcontroller_config = config.perform(context)
|
||||||
|
with open(robotcontroller_config, 'r') as f:
|
||||||
|
axidraw_config = yaml.safe_load(f)['/axidraw_serial']['ros__parameters']
|
||||||
|
print(f'Loaded configuration: {axidraw_config}')
|
||||||
|
|
||||||
nodes = [
|
nodes = [
|
||||||
Node(
|
Node(
|
||||||
package="axidraw_controller",
|
package="axidraw_controller",
|
||||||
@@ -34,6 +42,7 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
arguments=["--ros-args", "--log-level", log_level],
|
arguments=["--ros-args", "--log-level", log_level],
|
||||||
parameters=[
|
parameters=[
|
||||||
{"serial_port": serial_port},
|
{"serial_port": serial_port},
|
||||||
|
axidraw_config,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ class AxidrawController : public RobotController
|
|||||||
this->penup_pub->publish(std_msgs::msg::Empty());
|
this->penup_pub->publish(std_msgs::msg::Empty());
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->pendown_pub->publish(std_msgs::msg::Empty());
|
//this->pendown_pub->publish(std_msgs::msg::Empty());
|
||||||
while (i + count + 1 < points.size() && points[i + count + 1].z <= 0)
|
while (i + count + 1 < points.size() && points[i + count + 1].z <= 0)
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class AxidrawSerial(Node):
|
|||||||
status = {
|
status = {
|
||||||
"serial": "not ready",
|
"serial": "not ready",
|
||||||
"motion": "waiting",
|
"motion": "waiting",
|
||||||
|
"pen": "up",
|
||||||
}
|
}
|
||||||
|
|
||||||
def init_serial(self, port):
|
def init_serial(self, port):
|
||||||
@@ -60,9 +61,22 @@ class AxidrawSerial(Node):
|
|||||||
return False
|
return False
|
||||||
self.ad.options.units = 2 # set working units to mm.
|
self.ad.options.units = 2 # set working units to mm.
|
||||||
self.ad.options.model = 2 # set model to AxiDraw V3/A3
|
self.ad.options.model = 2 # set model to AxiDraw V3/A3
|
||||||
|
|
||||||
|
self.ad.options.speed_pendown = self.get_parameter('axidraw_speed_pendown').get_parameter_value().integer_value # Maximum XY speed when the pen is down (plotting).
|
||||||
|
self.ad.options.speed_penup = self.get_parameter('axidraw_speed_penup').get_parameter_value().integer_value # Maximum XY speed when the pen is up.
|
||||||
|
self.ad.options.accel = self.get_parameter('axidraw_accel').get_parameter_value().integer_value # Relative acceleration/deceleration speed.
|
||||||
|
#self.get_logger().error('accel:{}'.format(self.get_parameter('axidraw_accel').get_parameter_value().integer_value))
|
||||||
|
self.ad.options.pen_pos_down = self.get_parameter('axidraw_pen_pos_down').get_parameter_value().integer_value #Pen height when the pen is down (plotting).
|
||||||
|
self.ad.options.pen_pos_up = self.get_parameter('axidraw_pen_pos_up').get_parameter_value().integer_value #Pen height when the pen is up.
|
||||||
|
self.ad.options.pen_rate_lower = self.get_parameter('axidraw_pen_rate_lower').get_parameter_value().integer_value # Speed of lowering the pen-lift motor.
|
||||||
|
self.ad.options.pen_rate_raise = self.get_parameter('axidraw_pen_rate_raise').get_parameter_value().integer_value #Speed of raising the pen-lift motor.
|
||||||
|
self.ad.options.const_speed = self.get_parameter('axidraw_const_speed').get_parameter_value().bool_value #Option: Use constant speed when pen is down.
|
||||||
|
self.ad.options.pen_delay_down = self.get_parameter('axidraw_pen_delay_down').get_parameter_value().integer_value #Added delay after lowering pen.
|
||||||
|
self.ad.options.pen_delay_up = self.get_parameter('axidraw_pen_delay_up').get_parameter_value().integer_value #Added delay after raising pen.
|
||||||
self.ad.update() # Process changes to options
|
self.ad.update() # Process changes to options
|
||||||
self.status["serial"] = "ready"
|
self.status["serial"] = "ready"
|
||||||
self.status["motion"] = "ready"
|
self.status["motion"] = "ready"
|
||||||
|
self.status["pen"] = "up"
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -80,10 +94,22 @@ class AxidrawSerial(Node):
|
|||||||
self.declare_parameter('serial_port', '/dev/ttyACM0')
|
self.declare_parameter('serial_port', '/dev/ttyACM0')
|
||||||
port = self.get_parameter('serial_port').get_parameter_value().string_value
|
port = self.get_parameter('serial_port').get_parameter_value().string_value
|
||||||
|
|
||||||
|
self.declare_parameter('axidraw_speed_pendown', 100)
|
||||||
|
self.declare_parameter('axidraw_speed_penup', 100)
|
||||||
|
self.declare_parameter('axidraw_accel', 100)
|
||||||
|
self.declare_parameter('axidraw_pen_pos_down', 40)
|
||||||
|
self.declare_parameter('axidraw_pen_pos_up', 60)
|
||||||
|
self.declare_parameter('axidraw_pen_rate_lower', 50)
|
||||||
|
self.declare_parameter('axidraw_pen_rate_raise', 75)
|
||||||
|
self.declare_parameter('axidraw_const_speed', False)
|
||||||
|
self.declare_parameter('axidraw_pen_delay_down', 0)
|
||||||
|
self.declare_parameter('axidraw_pen_delay_up', 0)
|
||||||
|
|
||||||
self.status_srv = self.create_service(Status, 'axidraw_status', self.get_status)
|
self.status_srv = self.create_service(Status, 'axidraw_status', self.get_status)
|
||||||
|
|
||||||
while not self.init_serial(port):
|
while not self.init_serial(port):
|
||||||
self.get_logger().error("Failed to connect to axidraw on port:{}".format(port))
|
self.get_logger().error("Failed to connect to axidraw on port:{}, retrying".format(port))
|
||||||
|
self.get_logger().info("Successfully connected to axidraw on port:{}".format(port))
|
||||||
|
|
||||||
self.move_sub = self.create_subscription(Point, 'axidraw_move', self.move_callback, qos_profile=QoSProfile(depth=1))
|
self.move_sub = self.create_subscription(Point, 'axidraw_move', self.move_callback, qos_profile=QoSProfile(depth=1))
|
||||||
self.penup_sub = self.create_subscription(Empty, 'axidraw_penup', self.penup_callback, qos_profile=QoSProfile(depth=1))
|
self.penup_sub = self.create_subscription(Empty, 'axidraw_penup', self.penup_callback, qos_profile=QoSProfile(depth=1))
|
||||||
@@ -165,7 +191,9 @@ class AxidrawSerial(Node):
|
|||||||
|
|
||||||
self.get_logger().info("Received penup: {}".format(msg))
|
self.get_logger().info("Received penup: {}".format(msg))
|
||||||
|
|
||||||
self.ad.penup()
|
if self.status['pen'] == "down":
|
||||||
|
self.ad.penup()
|
||||||
|
self.status['pen'] = "up"
|
||||||
self.set_ready()
|
self.set_ready()
|
||||||
|
|
||||||
def pendown_callback(self, msg):
|
def pendown_callback(self, msg):
|
||||||
@@ -178,7 +206,9 @@ class AxidrawSerial(Node):
|
|||||||
|
|
||||||
self.get_logger().info("Received pendown: {}".format(msg))
|
self.get_logger().info("Received pendown: {}".format(msg))
|
||||||
|
|
||||||
self.ad.pendown()
|
if self.status['pen'] == "up":
|
||||||
|
self.ad.pendown()
|
||||||
|
self.status['pen'] = "down"
|
||||||
self.set_ready()
|
self.set_ready()
|
||||||
|
|
||||||
def stroke_callback(self, msg):
|
def stroke_callback(self, msg):
|
||||||
@@ -193,6 +223,7 @@ class AxidrawSerial(Node):
|
|||||||
|
|
||||||
path = [ [p.x,p.y] for p in msg.points ]
|
path = [ [p.x,p.y] for p in msg.points ]
|
||||||
self.ad.draw_path(path)
|
self.ad.draw_path(path)
|
||||||
|
self.status['pen'] = "up"
|
||||||
self.set_ready()
|
self.set_ready()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
cartesian_limits:
|
||||||
|
max_trans_vel: 0.4
|
||||||
|
max_trans_acc: 4.00
|
||||||
|
max_trans_dec: -5.0
|
||||||
|
max_rot_vel: 1.57
|
||||||
@@ -4,31 +4,31 @@
|
|||||||
joint_limits:
|
joint_limits:
|
||||||
joint1:
|
joint1:
|
||||||
has_velocity_limits: true
|
has_velocity_limits: true
|
||||||
max_velocity: 2.14
|
max_velocity: 4.14
|
||||||
has_acceleration_limits: true
|
has_acceleration_limits: true
|
||||||
max_acceleration: 1.0
|
max_acceleration: 30.0
|
||||||
joint2:
|
joint2:
|
||||||
has_velocity_limits: true
|
has_velocity_limits: true
|
||||||
max_velocity: 2.14
|
max_velocity: 4.14
|
||||||
has_acceleration_limits: true
|
has_acceleration_limits: true
|
||||||
max_acceleration: 1.0
|
max_acceleration: 30.0
|
||||||
joint3:
|
joint3:
|
||||||
has_velocity_limits: true
|
has_velocity_limits: true
|
||||||
max_velocity: 2.14
|
max_velocity: 4.14
|
||||||
has_acceleration_limits: true
|
has_acceleration_limits: true
|
||||||
max_acceleration: 1.0
|
max_acceleration: 30.0
|
||||||
joint4:
|
joint4:
|
||||||
has_velocity_limits: true
|
has_velocity_limits: true
|
||||||
max_velocity: 2.14
|
max_velocity: 4.14
|
||||||
has_acceleration_limits: true
|
has_acceleration_limits: true
|
||||||
max_acceleration: 1.0
|
max_acceleration: 30.0
|
||||||
joint5:
|
joint5:
|
||||||
has_velocity_limits: true
|
has_velocity_limits: true
|
||||||
max_velocity: 2.14
|
max_velocity: 4.14
|
||||||
has_acceleration_limits: true
|
has_acceleration_limits: true
|
||||||
max_acceleration: 1.0
|
max_acceleration: 30.0
|
||||||
joint6:
|
joint6:
|
||||||
has_velocity_limits: true
|
has_velocity_limits: true
|
||||||
max_velocity: 2.14
|
max_velocity: 4.14
|
||||||
has_acceleration_limits: true
|
has_acceleration_limits: true
|
||||||
max_acceleration: 1.0
|
max_acceleration: 30.0
|
||||||
|
|||||||
@@ -65,19 +65,22 @@ def add_prefix_to_moveit_params(controllers_yaml=None, ompl_planning_yaml=None,
|
|||||||
|
|
||||||
|
|
||||||
def get_xarm_robot_description_parameters(
|
def get_xarm_robot_description_parameters(
|
||||||
xacro_urdf_file=PathJoinSubstitution([FindPackageShare('xarm_description'), 'urdf', 'xarm_device.urdf.xacro']),
|
xacro_urdf_file=PathJoinSubstitution([FindPackageShare('custom_xarm_description'), 'urdf', 'xarm_device.urdf.xacro']),
|
||||||
xacro_srdf_file=PathJoinSubstitution([FindPackageShare('xarm_moveit_config'), 'srdf', 'xarm.srdf.xacro']),
|
xacro_srdf_file=PathJoinSubstitution([FindPackageShare('custom_xarm_moveit_config'), 'srdf', 'xarm.srdf.xacro']),
|
||||||
urdf_arguments={},
|
urdf_arguments={},
|
||||||
srdf_arguments={},
|
srdf_arguments={},
|
||||||
arguments={}):
|
arguments={}):
|
||||||
urdf_arguments['ros2_control_plugin'] = urdf_arguments.get('ros2_control_plugin', 'uf_robot_hardware/UFRobotSystemHardware')
|
urdf_arguments['ros2_control_plugin'] = urdf_arguments.get('ros2_control_plugin', 'uf_robot_hardware/UFRobotSystemHardware')
|
||||||
moveit_config_package_name = 'xarm_moveit_config'
|
moveit_config_package_name = 'custom_xarm_moveit_config'
|
||||||
xarm_type = arguments.get('xarm_type', None)
|
xarm_type = arguments.get('xarm_type', None)
|
||||||
|
|
||||||
# xarm_description/launch/lib/robot_description_lib.py
|
# xarm_description/launch/lib/robot_description_lib.py
|
||||||
mod = load_python_launch_file_as_module(os.path.join(get_package_share_directory('xarm_description'), 'launch', 'lib', 'robot_description_lib.py'))
|
mod = load_python_launch_file_as_module(os.path.join(get_package_share_directory('custom_xarm_description'), 'launch', 'lib', 'robot_description_lib.py'))
|
||||||
get_xacro_file_content = getattr(mod, 'get_xacro_file_content')
|
get_xacro_file_content = getattr(mod, 'get_xacro_file_content')
|
||||||
|
|
||||||
|
joint_limits = load_yaml(moveit_config_package_name, 'config', xarm_type, 'joint_limits.yaml')
|
||||||
|
cartesian_limits = load_yaml(moveit_config_package_name, 'config', xarm_type, 'cartesian_limits.yaml')
|
||||||
|
joint_limits['cartesian_limits'] = cartesian_limits['cartesian_limits']
|
||||||
return {
|
return {
|
||||||
'robot_description': get_xacro_file_content(
|
'robot_description': get_xacro_file_content(
|
||||||
xacro_file=xacro_urdf_file,
|
xacro_file=xacro_urdf_file,
|
||||||
@@ -87,6 +90,6 @@ def get_xarm_robot_description_parameters(
|
|||||||
xacro_file=xacro_srdf_file,
|
xacro_file=xacro_srdf_file,
|
||||||
arguments=srdf_arguments
|
arguments=srdf_arguments
|
||||||
),
|
),
|
||||||
'robot_description_planning': load_yaml(moveit_config_package_name, 'config', xarm_type, 'joint_limits.yaml'),
|
'robot_description_planning': joint_limits,
|
||||||
'robot_description_kinematics': load_yaml(moveit_config_package_name, 'config', xarm_type, 'kinematics.yaml')
|
'robot_description_kinematics': load_yaml(moveit_config_package_name, 'config', xarm_type, 'kinematics.yaml')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ from robot_interfaces.msg import Motion
|
|||||||
import sys
|
import sys
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
from drawing_controller.svg_processor import SVGProcessor
|
from drawing_controller.svg_processor import SVGProcessor
|
||||||
|
|
||||||
def quaternion_from_euler(ai, aj, ak):
|
def quaternion_from_euler(ai, aj, ak):
|
||||||
@@ -61,13 +63,17 @@ class DrawingController(Node):
|
|||||||
def __init__(self, svgpath):
|
def __init__(self, svgpath):
|
||||||
super().__init__('drawing_controller')
|
super().__init__('drawing_controller')
|
||||||
#self.publisher_ = self.create_publisher(PoseStamped, '/target_pose', 10)
|
#self.publisher_ = self.create_publisher(PoseStamped, '/target_pose', 10)
|
||||||
timer_period = 1.0 # seconds
|
timer_period = 0.1 # seconds
|
||||||
self.timer = self.create_timer(timer_period, self.timer_callback)
|
self.timer = self.create_timer(timer_period, self.timer_callback)
|
||||||
self.i = 0
|
self.i = 0
|
||||||
self.busy = False
|
self.busy = False
|
||||||
|
|
||||||
self._action_client = ActionClient(self, ExecuteMotion, 'execute_motion')
|
self._action_client = ActionClient(self, ExecuteMotion, 'execute_motion')
|
||||||
|
|
||||||
|
self.results = {}
|
||||||
|
|
||||||
|
self.svg_start_time = time.time()
|
||||||
|
|
||||||
xml = ET.parse(svgpath)
|
xml = ET.parse(svgpath)
|
||||||
svg = xml.getroot()
|
svg = xml.getroot()
|
||||||
#self.map_point = map_point_function(float(svg.get('width')), float(svg.get('height')), 0.1, 0.5, -0.2, 0.2)
|
#self.map_point = map_point_function(float(svg.get('width')), float(svg.get('height')), 0.1, 0.5, -0.2, 0.2)
|
||||||
@@ -85,7 +91,11 @@ class DrawingController(Node):
|
|||||||
|
|
||||||
self.svg_processor = SVGProcessor(self.get_logger())
|
self.svg_processor = SVGProcessor(self.get_logger())
|
||||||
self.svg = self.svg_processor.process_svg(svgpath)
|
self.svg = self.svg_processor.process_svg(svgpath)
|
||||||
self.get_logger().info('Ready to begin executing motions')
|
self.results['svg path'] = svgpath
|
||||||
|
|
||||||
|
self.results['svg processing time'] = self.timestr(time.time() - self.svg_start_time)
|
||||||
|
self.start_time = time.time()
|
||||||
|
self.get_logger().info('SVG processing finished, executing motions')
|
||||||
|
|
||||||
def send_goal(self, motion):
|
def send_goal(self, motion):
|
||||||
self.busy = True
|
self.busy = True
|
||||||
@@ -101,22 +111,23 @@ class DrawingController(Node):
|
|||||||
def goal_response_callback(self, future):
|
def goal_response_callback(self, future):
|
||||||
goal_handle = future.result()
|
goal_handle = future.result()
|
||||||
if not goal_handle.accepted:
|
if not goal_handle.accepted:
|
||||||
self.get_logger().info('Goal rejected :(')
|
self.get_logger().debug('Goal rejected :(')
|
||||||
return
|
return
|
||||||
|
|
||||||
self.get_logger().info('Goal accepted :)')
|
self.get_logger().debug('Goal accepted :)')
|
||||||
|
|
||||||
self._get_result_future = goal_handle.get_result_async()
|
self._get_result_future = goal_handle.get_result_async()
|
||||||
self._get_result_future.add_done_callback(self.get_result_callback)
|
self._get_result_future.add_done_callback(self.get_result_callback)
|
||||||
|
|
||||||
def get_result_callback(self, future):
|
def get_result_callback(self, future):
|
||||||
result = future.result().result
|
result = future.result().result
|
||||||
self.get_logger().info('Result: {0}'.format(result))
|
self.results.update({ result.result: self.results.get(result.result, 0) + 1 })
|
||||||
|
self.get_logger().info('Result: {0}'.format(result.result))
|
||||||
self.busy = False
|
self.busy = False
|
||||||
|
|
||||||
def feedback_callback(self, feedback_msg):
|
def feedback_callback(self, feedback_msg):
|
||||||
feedback = feedback_msg.feedback
|
feedback = feedback_msg.feedback
|
||||||
self.get_logger().info('Received feedback: {0}'.format(feedback))
|
self.get_logger().debug('Received feedback: {0}'.format(feedback))
|
||||||
|
|
||||||
def append_points(self, motion, points):
|
def append_points(self, motion, points):
|
||||||
for point in points:
|
for point in points:
|
||||||
@@ -135,17 +146,23 @@ class DrawingController(Node):
|
|||||||
ps.pose = p
|
ps.pose = p
|
||||||
motion.path.append(ps)
|
motion.path.append(ps)
|
||||||
|
|
||||||
|
def timestr(self, t):
|
||||||
|
return time.strftime("%H:%M:%S", time.gmtime(t))
|
||||||
|
|
||||||
def timer_callback(self):
|
def timer_callback(self):
|
||||||
if self.busy:
|
if self.busy:
|
||||||
return
|
return
|
||||||
if self.i >= len(self.svg):
|
if self.i >= len(self.svg):
|
||||||
|
self.results['total time'] = self.timestr(time.time() - self.svg_start_time)
|
||||||
|
self.results['drawing time'] = self.timestr(time.time() - self.start_time)
|
||||||
self.get_logger().info('Finished executing all motions from SVG')
|
self.get_logger().info('Finished executing all motions from SVG')
|
||||||
|
self.get_logger().info('Results: {}'.format(self.results))
|
||||||
exit()
|
exit()
|
||||||
next_motion = self.svg[self.i]
|
next_motion = self.svg[self.i]
|
||||||
motion = Motion()
|
motion = Motion()
|
||||||
self.append_points(motion, next_motion)
|
self.append_points(motion, next_motion)
|
||||||
self.i = self.i + 1
|
self.i = self.i + 1
|
||||||
self.get_logger().info('Executing motion: {}...'.format(motion.path[:10]))
|
self.get_logger().info('Executing motion: {}/{}'.format(self.i, len(self.svg)))
|
||||||
self.send_goal(motion)
|
self.send_goal(motion)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class SVGPathParser():
|
|||||||
self.map_point = map_point
|
self.map_point = map_point
|
||||||
|
|
||||||
def tokenize(self, pathstr):
|
def tokenize(self, pathstr):
|
||||||
self.logger.info("Tokenizing path :'{}...' with {} characters".format(pathstr[:40], len(pathstr)))
|
self.logger.debug("Tokenizing path :'{}...' with {} characters".format(pathstr[:40], len(pathstr)))
|
||||||
path = []
|
path = []
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(pathstr):
|
while i < len(pathstr):
|
||||||
@@ -53,7 +53,7 @@ class SVGPathParser():
|
|||||||
Returns:
|
Returns:
|
||||||
primitive_fn ():
|
primitive_fn ():
|
||||||
'''
|
'''
|
||||||
self.logger.info("Parsing path :'{}...' with {} tokens".format(path[:20], len(path)))
|
self.logger.debug("Parsing path :'{}...' with {} tokens".format(path[:20], len(path)))
|
||||||
x = 0.0
|
x = 0.0
|
||||||
y = 0.0
|
y = 0.0
|
||||||
i = 0
|
i = 0
|
||||||
@@ -114,13 +114,13 @@ class SVGPathParser():
|
|||||||
#print('inpput', control_points)
|
#print('inpput', control_points)
|
||||||
maxval = np.amax(np.absolute(control_points))
|
maxval = np.amax(np.absolute(control_points))
|
||||||
#print('maxxv', maxval)
|
#print('maxxv', maxval)
|
||||||
control_points = control_points / maxval #normalize values
|
#control_points = control_points / maxval #normalize values
|
||||||
n = 50
|
n = 100
|
||||||
curve = cf.cubic_curve(control_points)
|
curve = cf.bezier(control_points)
|
||||||
lin = np.linspace(curve.start(0), curve.end(0), n)
|
lin = np.linspace(curve.start(0), curve.end(0), n)
|
||||||
coordinates = curve(lin)
|
coordinates = curve(lin)
|
||||||
coordinates = np.nan_to_num(coordinates)
|
coordinates = np.nan_to_num(coordinates)
|
||||||
coordinates = coordinates * maxval #denormalize values
|
#coordinates = coordinates * maxval #denormalize values
|
||||||
coordinates = dropzeros(coordinates)
|
coordinates = dropzeros(coordinates)
|
||||||
#self.logger.info("Appending curve points: {}".format(coordinates))
|
#self.logger.info("Appending curve points: {}".format(coordinates))
|
||||||
#print(coordinates)
|
#print(coordinates)
|
||||||
@@ -136,6 +136,20 @@ class SVGPathParser():
|
|||||||
x = coordinates[-1][0]
|
x = coordinates[-1][0]
|
||||||
y = coordinates[-1][1]
|
y = coordinates[-1][1]
|
||||||
return coordinates
|
return coordinates
|
||||||
|
def quadratic_bezier(control_points):
|
||||||
|
nonlocal x
|
||||||
|
nonlocal y
|
||||||
|
control_points = np.array(control_points)
|
||||||
|
n = 100
|
||||||
|
curve = cf.bezier(control_points, quadratic=True)
|
||||||
|
lin = np.linspace(curve.start(0), curve.end(0), n)
|
||||||
|
coordinates = curve(lin)
|
||||||
|
coordinates = np.nan_to_num(coordinates)
|
||||||
|
coordinates = dropzeros(coordinates)
|
||||||
|
if len(coordinates) > 0:
|
||||||
|
x = coordinates[-1][0]
|
||||||
|
y = coordinates[-1][1]
|
||||||
|
return coordinates
|
||||||
|
|
||||||
while i < len(path):
|
while i < len(path):
|
||||||
w = path[i]
|
w = path[i]
|
||||||
@@ -208,7 +222,6 @@ class SVGPathParser():
|
|||||||
# Cubic Bézier Curve commands
|
# Cubic Bézier Curve commands
|
||||||
if (w == "C"):
|
if (w == "C"):
|
||||||
while True:
|
while True:
|
||||||
# https://github.com/sintef/Splipy/tree/master/examples
|
|
||||||
control_points = [(x,y),
|
control_points = [(x,y),
|
||||||
(getnum(),getnum()),
|
(getnum(),getnum()),
|
||||||
(getnum(),getnum()),
|
(getnum(),getnum()),
|
||||||
@@ -221,7 +234,6 @@ class SVGPathParser():
|
|||||||
continue
|
continue
|
||||||
if (w == "c"):
|
if (w == "c"):
|
||||||
while True:
|
while True:
|
||||||
# https://github.com/sintef/Splipy/tree/master/examples
|
|
||||||
control_points = [(x,y),
|
control_points = [(x,y),
|
||||||
(x + getnum(), y + getnum()),
|
(x + getnum(), y + getnum()),
|
||||||
(x + getnum(), y + getnum()),
|
(x + getnum(), y + getnum()),
|
||||||
@@ -238,9 +250,27 @@ class SVGPathParser():
|
|||||||
self.logger.error("SVG path parser '{}' not implemented".format(w))
|
self.logger.error("SVG path parser '{}' not implemented".format(w))
|
||||||
# Quadratic Bézier Curve commands
|
# Quadratic Bézier Curve commands
|
||||||
if (w == "Q"):
|
if (w == "Q"):
|
||||||
self.logger.error("SVG path parser '{}' not implemented".format(w))
|
while True:
|
||||||
|
control_points = [(x,y),
|
||||||
|
(getnum(),getnum()),
|
||||||
|
(getnum(),getnum())]
|
||||||
|
coordinates = quadratic_bezier(control_points)
|
||||||
|
appendpoints(coordinates)
|
||||||
|
if not nextisnum():
|
||||||
|
break
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
if (w == "q"):
|
if (w == "q"):
|
||||||
self.logger.error("SVG path parser '{}' not implemented".format(w))
|
while True:
|
||||||
|
control_points = [(x,y),
|
||||||
|
(x + getnum(), y + getnum()),
|
||||||
|
(x + getnum(), y + getnum())]
|
||||||
|
coordinates = quadratic_bezier(control_points)
|
||||||
|
appendpoints(coordinates)
|
||||||
|
if not nextisnum():
|
||||||
|
break
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
if (w == "T"):
|
if (w == "T"):
|
||||||
self.logger.error("SVG path parser '{}' not implemented".format(w))
|
self.logger.error("SVG path parser '{}' not implemented".format(w))
|
||||||
if (w == "t"):
|
if (w == "t"):
|
||||||
@@ -259,5 +289,5 @@ class SVGPathParser():
|
|||||||
self.logger.error("SVG path parser panic mode at '{}'".format(w))
|
self.logger.error("SVG path parser panic mode at '{}'".format(w))
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
self.logger.info("Finished parsing path :'{}...' with {} points".format(output[:3], len(output)))
|
self.logger.debug("Finished parsing path :'{}...' with {} points".format(output[:3], len(output)))
|
||||||
return output
|
return output
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ class SVGProcessor():
|
|||||||
def remove_redundant(self, motion):
|
def remove_redundant(self, motion):
|
||||||
# Remove points that are too close to the previous point, specified by the tolerance
|
# Remove points that are too close to the previous point, specified by the tolerance
|
||||||
mm = []
|
mm = []
|
||||||
tolerance = 0.001
|
tolerance = 0.0001
|
||||||
prev = (-1, -1, 0)
|
prev = (-1, -1, 0)
|
||||||
for i, p in enumerate(motion):
|
for i, p in enumerate(motion):
|
||||||
x = p[0]
|
x = p[0]
|
||||||
@@ -197,8 +197,7 @@ class SVGProcessor():
|
|||||||
Simplify line with https://pypi.org/project/simplification/
|
Simplify line with https://pypi.org/project/simplification/
|
||||||
"""
|
"""
|
||||||
# For RDP, Try an epsilon of 1.0 to start with. Other sensible values include 0.01, 0.001
|
# For RDP, Try an epsilon of 1.0 to start with. Other sensible values include 0.01, 0.001
|
||||||
#epsilon = 0.009
|
epsilon = 0.00005
|
||||||
epsilon = 0.005
|
|
||||||
|
|
||||||
tmp = []
|
tmp = []
|
||||||
out = []
|
out = []
|
||||||
@@ -215,6 +214,7 @@ class SVGProcessor():
|
|||||||
tmp.append(list(p)[:-1])
|
tmp.append(list(p)[:-1])
|
||||||
lastup = penup
|
lastup = penup
|
||||||
|
|
||||||
|
# Handle anything left in tmp
|
||||||
if (len(tmp) > 0):
|
if (len(tmp) > 0):
|
||||||
out += sf(tmp)
|
out += sf(tmp)
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ find_package(moveit REQUIRED)
|
|||||||
find_package(pilz_industrial_motion_planner REQUIRED)
|
find_package(pilz_industrial_motion_planner REQUIRED)
|
||||||
find_package(moveit_msgs REQUIRED)
|
find_package(moveit_msgs REQUIRED)
|
||||||
find_package(geometry_msgs REQUIRED)
|
find_package(geometry_msgs REQUIRED)
|
||||||
|
find_package(xarm_api REQUIRED)
|
||||||
|
find_package(xarm_msgs REQUIRED)
|
||||||
|
|
||||||
find_package(tf2_ros REQUIRED)
|
find_package(tf2_ros REQUIRED)
|
||||||
find_package(geometry_msgs REQUIRED)
|
find_package(geometry_msgs REQUIRED)
|
||||||
@@ -45,6 +47,19 @@ ament_target_dependencies(lite6_controller
|
|||||||
"moveit_ros_planning_interface"
|
"moveit_ros_planning_interface"
|
||||||
"robot_interfaces")
|
"robot_interfaces")
|
||||||
|
|
||||||
|
add_executable(lite6_calibration src/lite6_calibration.cpp)
|
||||||
|
ament_target_dependencies(lite6_calibration
|
||||||
|
"xarm_msgs"
|
||||||
|
"xarm_api"
|
||||||
|
"rclcpp"
|
||||||
|
"moveit"
|
||||||
|
"rclcpp_action"
|
||||||
|
"Eigen3"
|
||||||
|
"pilz_industrial_motion_planner"
|
||||||
|
"robot_controller"
|
||||||
|
"moveit_ros_planning_interface"
|
||||||
|
"robot_interfaces")
|
||||||
|
|
||||||
if(BUILD_TESTING)
|
if(BUILD_TESTING)
|
||||||
find_package(ament_lint_auto REQUIRED)
|
find_package(ament_lint_auto REQUIRED)
|
||||||
ament_lint_auto_find_test_dependencies()
|
ament_lint_auto_find_test_dependencies()
|
||||||
@@ -52,8 +67,14 @@ endif()
|
|||||||
|
|
||||||
install(TARGETS
|
install(TARGETS
|
||||||
lite6_controller
|
lite6_controller
|
||||||
|
lite6_calibration
|
||||||
DESTINATION lib/${PROJECT_NAME})
|
DESTINATION lib/${PROJECT_NAME})
|
||||||
|
|
||||||
install(DIRECTORY launch DESTINATION share/${PROJECT_NAME})
|
install(DIRECTORY launch DESTINATION share/${PROJECT_NAME})
|
||||||
|
|
||||||
|
install(DIRECTORY
|
||||||
|
config
|
||||||
|
DESTINATION share/${PROJECT_NAME}
|
||||||
|
)
|
||||||
|
|
||||||
ament_package()
|
ament_package()
|
||||||
|
|||||||
13
src/lite6_controller/config/config.yaml
Normal file
13
src/lite6_controller/config/config.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/robot_controller:
|
||||||
|
ros__parameters:
|
||||||
|
lite6_x_limit_lower: 0.1
|
||||||
|
lite6_x_limit_upper: 0.305
|
||||||
|
lite6_y_limit_lower: -0.1475
|
||||||
|
lite6_y_limit_upper: 0.1475
|
||||||
|
|
||||||
|
lite6_z_lift_amount: 0.01
|
||||||
|
lite6_z_offset: 0.1475
|
||||||
|
|
||||||
|
lite6_blend_radius: 0.0
|
||||||
|
lite6_max_velocity_scaling_factor: 1.0
|
||||||
|
lite6_max_acceleration_scaling_factor: 0.9
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
"""Launch Python example for following a target"""
|
"""Launch Python example for following a target"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import yaml
|
||||||
from ament_index_python import get_package_share_directory
|
from ament_index_python import get_package_share_directory
|
||||||
from launch.launch_description_sources import load_python_launch_file_as_module
|
from launch.launch_description_sources import load_python_launch_file_as_module
|
||||||
from launch import LaunchDescription
|
from launch import LaunchDescription
|
||||||
@@ -17,7 +18,8 @@ from launch.actions import OpaqueFunction
|
|||||||
def launch_setup(context, *args, **kwargs):
|
def launch_setup(context, *args, **kwargs):
|
||||||
use_sim_time = LaunchConfiguration("use_sim_time", default=True)
|
use_sim_time = LaunchConfiguration("use_sim_time", default=True)
|
||||||
log_level = LaunchConfiguration("log_level", default='info')
|
log_level = LaunchConfiguration("log_level", default='info')
|
||||||
rviz_config = LaunchConfiguration('rviz_config', default=os.path.join(get_package_share_directory("draw_svg"), "rviz", "ign_moveit2_examples.rviz"))
|
rviz_config = LaunchConfiguration('rviz_config', default=os.path.join(get_package_share_directory("custom_xarm_description"), "rviz", "display.rviz"))
|
||||||
|
|
||||||
|
|
||||||
prefix = LaunchConfiguration('prefix', default='')
|
prefix = LaunchConfiguration('prefix', default='')
|
||||||
hw_ns = LaunchConfiguration('hw_ns', default='xarm')
|
hw_ns = LaunchConfiguration('hw_ns', default='xarm')
|
||||||
@@ -54,6 +56,8 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
moveit_controller_manager_key = LaunchConfiguration('moveit_controller_manager_key', default='moveit_simple_controller_manager')
|
moveit_controller_manager_key = LaunchConfiguration('moveit_controller_manager_key', default='moveit_simple_controller_manager')
|
||||||
moveit_controller_manager_value = LaunchConfiguration('moveit_controller_manager_value', default='moveit_simple_controller_manager/MoveItSimpleControllerManager')
|
moveit_controller_manager_value = LaunchConfiguration('moveit_controller_manager_value', default='moveit_simple_controller_manager/MoveItSimpleControllerManager')
|
||||||
|
|
||||||
|
config = LaunchConfiguration("config", default=PathJoinSubstitution([FindPackageShare('lite6_controller'), 'config', 'config.yaml']))
|
||||||
|
|
||||||
# robot moveit common launch
|
# robot moveit common launch
|
||||||
# xarm_moveit_config/launch/_robot_moveit_common.launch.py
|
# xarm_moveit_config/launch/_robot_moveit_common.launch.py
|
||||||
robot_moveit_common_launch = IncludeLaunchDescription(
|
robot_moveit_common_launch = IncludeLaunchDescription(
|
||||||
@@ -263,10 +267,20 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
kinematics_yaml = robot_description_parameters['robot_description_kinematics']
|
kinematics_yaml = robot_description_parameters['robot_description_kinematics']
|
||||||
joint_limits_yaml = robot_description_parameters.get('robot_description_planning', None)
|
joint_limits_yaml = robot_description_parameters.get('robot_description_planning', None)
|
||||||
|
|
||||||
|
robotcontroller_config = config.perform(context)
|
||||||
|
with open(robotcontroller_config, 'r') as f:
|
||||||
|
lite6_config = yaml.safe_load(f)
|
||||||
|
print(f'Loaded configuration: {lite6_config}')
|
||||||
|
robot_description_parameters.update(lite6_config['/robot_controller']['ros__parameters'])
|
||||||
|
|
||||||
|
#cartesian_limits = load_yaml(moveit_config_package_name, 'config', xarm_type, 'cartesian_limits.yaml')
|
||||||
|
#robot_description_parameters['robot_description_planning']['cartesian_limits'] = cartesian_limits['cartesian_limits']
|
||||||
|
#input(joint_limits_yaml)
|
||||||
|
|
||||||
# FIX acceleration limits
|
# FIX acceleration limits
|
||||||
for i in range(1,7):
|
#for i in range(1,7):
|
||||||
joint_limits_yaml['joint_limits']['joint{}'.format(i)]['has_acceleration_limits'] = True
|
# joint_limits_yaml['joint_limits']['joint{}'.format(i)]['has_acceleration_limits'] = True
|
||||||
joint_limits_yaml['joint_limits']['joint{}'.format(i)]['max_acceleration'] = 1.0
|
# joint_limits_yaml['joint_limits']['joint{}'.format(i)]['max_acceleration'] = 1.0
|
||||||
|
|
||||||
kinematics_yaml['kinematics_solver'] = 'kdl_kinematics_plugin/KDLKinematicsPlugin'
|
kinematics_yaml['kinematics_solver'] = 'kdl_kinematics_plugin/KDLKinematicsPlugin'
|
||||||
#kinematics_yaml['kinematics_solver'] = 'lma_kinematics_plugin/LMAKinematicsPlugin'
|
#kinematics_yaml['kinematics_solver'] = 'lma_kinematics_plugin/LMAKinematicsPlugin'
|
||||||
@@ -300,12 +314,8 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
prefix=prefix.perform(context))
|
prefix=prefix.perform(context))
|
||||||
|
|
||||||
|
|
||||||
robot_description_parameters['cartesian_limits'] = {}
|
#cartesian_limits = load_yaml(moveit_config_package_name, 'config', xarm_type, 'cartesian_limits.yaml')
|
||||||
robot_description_parameters['cartesian_limits']['max_trans_vel'] = 1
|
#robot_description_parameters['robot_description_planning']['cartesian_limits'] = cartesian_limits['cartesian_limits']
|
||||||
robot_description_parameters['cartesian_limits']['max_trans_acc'] = 2.25
|
|
||||||
robot_description_parameters['cartesian_limits']['max_trans_dec'] = -5
|
|
||||||
robot_description_parameters['cartesian_limits']['max_rot_vel'] = 1.57
|
|
||||||
|
|
||||||
|
|
||||||
# Planning pipeline
|
# Planning pipeline
|
||||||
# https://github.com/AndrejOrsula/panda_moveit2_config/blob/master/launch/move_group_fake_control.launch.py
|
# https://github.com/AndrejOrsula/panda_moveit2_config/blob/master/launch/move_group_fake_control.launch.py
|
||||||
@@ -382,15 +392,8 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
'publish_geometry_updates': True,
|
'publish_geometry_updates': True,
|
||||||
'publish_state_updates': True,
|
'publish_state_updates': True,
|
||||||
'publish_transforms_updates': True,
|
'publish_transforms_updates': True,
|
||||||
# "planning_scene_monitor_options": {
|
'publish_robot_description': True,
|
||||||
# "name": "planning_scene_monitor",
|
'publish_robot_description_semantic' :True,
|
||||||
# "robot_description": "robot_description",
|
|
||||||
# "joint_state_topic": "/joint_states",
|
|
||||||
# "attached_collision_object_topic": "/move_group/planning_scene_monitor",
|
|
||||||
# "publish_planning_scene_topic": "/move_group/publish_planning_scene",
|
|
||||||
# "monitored_planning_scene_topic": "/move_group/monitored_planning_scene",
|
|
||||||
# "wait_for_initial_state_timeout": 10.0,
|
|
||||||
# },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Start the actual move_group node/action server
|
# Start the actual move_group node/action server
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
import yaml
|
||||||
from launch import LaunchDescription
|
from launch import LaunchDescription
|
||||||
from launch.actions import OpaqueFunction, IncludeLaunchDescription, DeclareLaunchArgument
|
from launch.actions import OpaqueFunction, IncludeLaunchDescription, DeclareLaunchArgument
|
||||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
||||||
@@ -15,6 +16,7 @@ from launch.events import Shutdown
|
|||||||
|
|
||||||
|
|
||||||
def launch_setup(context, *args, **kwargs):
|
def launch_setup(context, *args, **kwargs):
|
||||||
|
|
||||||
robot_ip = LaunchConfiguration('robot_ip', default='192.168.1.150')
|
robot_ip = LaunchConfiguration('robot_ip', default='192.168.1.150')
|
||||||
report_type = LaunchConfiguration('report_type', default='normal')
|
report_type = LaunchConfiguration('report_type', default='normal')
|
||||||
prefix = LaunchConfiguration('prefix', default='')
|
prefix = LaunchConfiguration('prefix', default='')
|
||||||
@@ -55,6 +57,8 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
use_sim_time = LaunchConfiguration('use_sim_time', default=False)
|
use_sim_time = LaunchConfiguration('use_sim_time', default=False)
|
||||||
log_level = LaunchConfiguration("log_level", default='warn')
|
log_level = LaunchConfiguration("log_level", default='warn')
|
||||||
|
|
||||||
|
config = LaunchConfiguration("config", default=PathJoinSubstitution([FindPackageShare('lite6_controller'), 'config', 'config.yaml']))
|
||||||
|
|
||||||
# # robot driver launch
|
# # robot driver launch
|
||||||
# # xarm_api/launch/_robot_driver.launch.py
|
# # xarm_api/launch/_robot_driver.launch.py
|
||||||
# robot_driver_launch = IncludeLaunchDescription(
|
# robot_driver_launch = IncludeLaunchDescription(
|
||||||
@@ -75,7 +79,7 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
# robot description launch
|
# robot description launch
|
||||||
# xarm_description/launch/_robot_description.launch.py
|
# xarm_description/launch/_robot_description.launch.py
|
||||||
robot_description_launch = IncludeLaunchDescription(
|
robot_description_launch = IncludeLaunchDescription(
|
||||||
PythonLaunchDescriptionSource(PathJoinSubstitution([FindPackageShare('xarm_description'), 'launch', '_robot_description.launch.py'])),
|
PythonLaunchDescriptionSource(PathJoinSubstitution([FindPackageShare('custom_xarm_description'), 'launch', '_robot_description.launch.py'])),
|
||||||
launch_arguments={
|
launch_arguments={
|
||||||
'prefix': prefix,
|
'prefix': prefix,
|
||||||
'hw_ns': hw_ns,
|
'hw_ns': hw_ns,
|
||||||
@@ -105,12 +109,12 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
|
|
||||||
# robot_description_parameters
|
# robot_description_parameters
|
||||||
# xarm_moveit_config/launch/lib/robot_moveit_config_lib.py
|
# xarm_moveit_config/launch/lib/robot_moveit_config_lib.py
|
||||||
moveit_config_package_name = 'xarm_moveit_config'
|
moveit_config_package_name = 'custom_xarm_moveit_config'
|
||||||
mod = load_python_launch_file_as_module(os.path.join(get_package_share_directory(moveit_config_package_name), 'launch', 'lib', 'robot_moveit_config_lib.py'))
|
mod = load_python_launch_file_as_module(os.path.join(get_package_share_directory(moveit_config_package_name), 'launch', 'lib', 'robot_moveit_config_lib.py'))
|
||||||
get_xarm_robot_description_parameters = getattr(mod, 'get_xarm_robot_description_parameters')
|
get_xarm_robot_description_parameters = getattr(mod, 'get_xarm_robot_description_parameters')
|
||||||
robot_description_parameters = get_xarm_robot_description_parameters(
|
robot_description_parameters = get_xarm_robot_description_parameters(
|
||||||
xacro_urdf_file=PathJoinSubstitution([FindPackageShare('xarm_description'), 'urdf', 'xarm_device.urdf.xacro']),
|
xacro_urdf_file=PathJoinSubstitution([FindPackageShare('custom_xarm_description'), 'urdf', 'xarm_device.urdf.xacro']),
|
||||||
xacro_srdf_file=PathJoinSubstitution([FindPackageShare('xarm_moveit_config'), 'srdf', 'xarm.srdf.xacro']),
|
xacro_srdf_file=PathJoinSubstitution([FindPackageShare('custom_xarm_moveit_config'), 'srdf', 'xarm.srdf.xacro']),
|
||||||
urdf_arguments={
|
urdf_arguments={
|
||||||
'prefix': prefix,
|
'prefix': prefix,
|
||||||
'hw_ns': hw_ns.perform(context).strip('/'),
|
'hw_ns': hw_ns.perform(context).strip('/'),
|
||||||
@@ -154,21 +158,22 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
ompl_planning_yaml = load_yaml(moveit_config_package_name, 'config', xarm_type, 'ompl_planning.yaml')
|
ompl_planning_yaml = load_yaml(moveit_config_package_name, 'config', xarm_type, 'ompl_planning.yaml')
|
||||||
kinematics_yaml = robot_description_parameters['robot_description_kinematics']
|
kinematics_yaml = robot_description_parameters['robot_description_kinematics']
|
||||||
|
|
||||||
robot_description_parameters['cartesian_limits'] = {}
|
kinematics_yaml['kinematics_solver'] = 'kdl_kinematics_plugin/KDLKinematicsPlugin'
|
||||||
robot_description_parameters['cartesian_limits']['max_trans_vel'] = 1
|
kinematics_yaml['kinematics_solver_search_resolution'] = 0.005
|
||||||
robot_description_parameters['cartesian_limits']['max_trans_acc'] = 2.25
|
kinematics_yaml['kinematics_solver_timeout'] = 0.005
|
||||||
robot_description_parameters['cartesian_limits']['max_trans_dec'] = -5
|
kinematics_yaml['kinematics_solver_attempts'] = 3
|
||||||
robot_description_parameters['cartesian_limits']['max_rot_vel'] = 1.57
|
|
||||||
|
|
||||||
#kinematics_yaml['kinematics_solver'] = 'kdl_kinematics_plugin/KDLKinematicsPlugin'
|
|
||||||
#kinematics_yaml['kinematics_solver_search_resolution'] = 0.005
|
|
||||||
#kinematics_yaml['kinematics_solver_timeout'] = 0.005
|
|
||||||
#kinematics_yaml['kinematics_solver_attempts'] = 3
|
|
||||||
kinematics_yaml['kinematics_solver_timeout'] = 10.0
|
kinematics_yaml['kinematics_solver_timeout'] = 10.0
|
||||||
|
|
||||||
kinematics_yaml['kinematics_solver_attempts'] = 10
|
kinematics_yaml['kinematics_solver_attempts'] = 10
|
||||||
|
|
||||||
joint_limits_yaml = robot_description_parameters.get('robot_description_planning', None)
|
joint_limits_yaml = robot_description_parameters.get('robot_description_planning', None)
|
||||||
|
|
||||||
|
robotcontroller_config = config.perform(context)
|
||||||
|
with open(robotcontroller_config, 'r') as f:
|
||||||
|
lite6_config = yaml.safe_load(f)
|
||||||
|
print(f'Loaded configuration: {lite6_config}')
|
||||||
|
robot_description_parameters.update(lite6_config['/robot_controller']['ros__parameters'])
|
||||||
|
|
||||||
if add_gripper.perform(context) in ('True', 'true'):
|
if add_gripper.perform(context) in ('True', 'true'):
|
||||||
gripper_controllers_yaml = load_yaml(moveit_config_package_name, 'config', '{}_gripper'.format(robot_type.perform(context)), '{}.yaml'.format(controllers_name.perform(context)))
|
gripper_controllers_yaml = load_yaml(moveit_config_package_name, 'config', '{}_gripper'.format(robot_type.perform(context)), '{}.yaml'.format(controllers_name.perform(context)))
|
||||||
gripper_ompl_planning_yaml = load_yaml(moveit_config_package_name, 'config', '{}_gripper'.format(robot_type.perform(context)), 'ompl_planning.yaml')
|
gripper_ompl_planning_yaml = load_yaml(moveit_config_package_name, 'config', '{}_gripper'.format(robot_type.perform(context)), 'ompl_planning.yaml')
|
||||||
@@ -186,11 +191,11 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
joint_limits_yaml['joint_limits'].update(gripper_joint_limits_yaml['joint_limits'])
|
joint_limits_yaml['joint_limits'].update(gripper_joint_limits_yaml['joint_limits'])
|
||||||
|
|
||||||
# FIX acceleration limits
|
# FIX acceleration limits
|
||||||
for i in range(1,7):
|
#for i in range(1,7):
|
||||||
joint_limits_yaml['joint_limits']['joint{}'.format(i)]['has_acceleration_limits'] = True
|
# joint_limits_yaml['joint_limits']['joint{}'.format(i)]['has_acceleration_limits'] = True
|
||||||
#joint_limits_yaml['joint_limits']['joint{}'.format(i)]['max_acceleration'] = 1.5
|
# #joint_limits_yaml['joint_limits']['joint{}'.format(i)]['max_acceleration'] = 1.5
|
||||||
#joint_limits_yaml['joint_limits']['joint{}'.format(i)]['max_acceleration'] = 2.5
|
# #joint_limits_yaml['joint_limits']['joint{}'.format(i)]['max_acceleration'] = 2.5
|
||||||
joint_limits_yaml['joint_limits']['joint{}'.format(i)]['max_acceleration'] = 3.0
|
# joint_limits_yaml['joint_limits']['joint{}'.format(i)]['max_acceleration'] = 3.0
|
||||||
|
|
||||||
add_prefix_to_moveit_params = getattr(mod, 'add_prefix_to_moveit_params')
|
add_prefix_to_moveit_params = getattr(mod, 'add_prefix_to_moveit_params')
|
||||||
add_prefix_to_moveit_params(
|
add_prefix_to_moveit_params(
|
||||||
@@ -232,15 +237,8 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
'publish_geometry_updates': True,
|
'publish_geometry_updates': True,
|
||||||
'publish_state_updates': True,
|
'publish_state_updates': True,
|
||||||
'publish_transforms_updates': True,
|
'publish_transforms_updates': True,
|
||||||
# "planning_scene_monitor_options": {
|
'publish_robot_description': True,
|
||||||
# "name": "planning_scene_monitor",
|
'publish_robot_description_semantic' :True,
|
||||||
# "robot_description": "robot_description",
|
|
||||||
# "joint_state_topic": "/joint_states",
|
|
||||||
# "attached_collision_object_topic": "/move_group/planning_scene_monitor",
|
|
||||||
# "publish_planning_scene_topic": "/move_group/publish_planning_scene",
|
|
||||||
# "monitored_planning_scene_topic": "/move_group/monitored_planning_scene",
|
|
||||||
# "wait_for_initial_state_timeout": 10.0,
|
|
||||||
# },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -249,7 +247,8 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
'planning_plugin': 'pilz_industrial_motion_planner/CommandPlanner',
|
'planning_plugin': 'pilz_industrial_motion_planner/CommandPlanner',
|
||||||
#'request_adapters': """default_planner_request_adapters/AddTimeOptimalParameterization default_planner_request_adapters/FixWorkspaceBounds default_planner_request_adapters/FixStartStateBounds default_planner_request_adapters/FixStartStateCollision default_planner_request_adapters/FixStartStatePathConstraints""",
|
#'request_adapters': """default_planner_request_adapters/AddTimeOptimalParameterization default_planner_request_adapters/FixWorkspaceBounds default_planner_request_adapters/FixStartStateBounds default_planner_request_adapters/FixStartStateCollision default_planner_request_adapters/FixStartStatePathConstraints""",
|
||||||
'request_adapters': """default_planner_request_adapters/FixWorkspaceBounds default_planner_request_adapters/FixStartStateBounds default_planner_request_adapters/FixStartStateCollision default_planner_request_adapters/FixStartStatePathConstraints""",
|
'request_adapters': """default_planner_request_adapters/FixWorkspaceBounds default_planner_request_adapters/FixStartStateBounds default_planner_request_adapters/FixStartStateCollision default_planner_request_adapters/FixStartStatePathConstraints""",
|
||||||
"default_planner_config": "PTP",
|
#"default_planner_config": "PTP",
|
||||||
|
"default_planner_config": "LIN",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,6 +263,7 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
output='screen',
|
output='screen',
|
||||||
parameters=[
|
parameters=[
|
||||||
robot_description_parameters,
|
robot_description_parameters,
|
||||||
|
#cartesian_limits,
|
||||||
#ompl_planning_pipeline_config,
|
#ompl_planning_pipeline_config,
|
||||||
pilz_planning_pipeline_config,
|
pilz_planning_pipeline_config,
|
||||||
move_group_capabilities,
|
move_group_capabilities,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
import yaml
|
||||||
from launch import LaunchDescription
|
from launch import LaunchDescription
|
||||||
from launch.actions import OpaqueFunction, IncludeLaunchDescription, DeclareLaunchArgument
|
from launch.actions import OpaqueFunction, IncludeLaunchDescription, DeclareLaunchArgument
|
||||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
||||||
@@ -15,6 +16,7 @@ from launch.events import Shutdown
|
|||||||
|
|
||||||
|
|
||||||
def launch_setup(context, *args, **kwargs):
|
def launch_setup(context, *args, **kwargs):
|
||||||
|
|
||||||
robot_ip = LaunchConfiguration('robot_ip', default='192.168.1.150')
|
robot_ip = LaunchConfiguration('robot_ip', default='192.168.1.150')
|
||||||
report_type = LaunchConfiguration('report_type', default='normal')
|
report_type = LaunchConfiguration('report_type', default='normal')
|
||||||
prefix = LaunchConfiguration('prefix', default='')
|
prefix = LaunchConfiguration('prefix', default='')
|
||||||
@@ -55,6 +57,8 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
use_sim_time = LaunchConfiguration('use_sim_time', default=False)
|
use_sim_time = LaunchConfiguration('use_sim_time', default=False)
|
||||||
log_level = LaunchConfiguration("log_level", default='warn')
|
log_level = LaunchConfiguration("log_level", default='warn')
|
||||||
|
|
||||||
|
config = LaunchConfiguration("config", default=PathJoinSubstitution([FindPackageShare('lite6_controller'), 'config', 'config.yaml']))
|
||||||
|
|
||||||
# # robot driver launch
|
# # robot driver launch
|
||||||
# # xarm_api/launch/_robot_driver.launch.py
|
# # xarm_api/launch/_robot_driver.launch.py
|
||||||
# robot_driver_launch = IncludeLaunchDescription(
|
# robot_driver_launch = IncludeLaunchDescription(
|
||||||
@@ -75,7 +79,7 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
# robot description launch
|
# robot description launch
|
||||||
# xarm_description/launch/_robot_description.launch.py
|
# xarm_description/launch/_robot_description.launch.py
|
||||||
robot_description_launch = IncludeLaunchDescription(
|
robot_description_launch = IncludeLaunchDescription(
|
||||||
PythonLaunchDescriptionSource(PathJoinSubstitution([FindPackageShare('xarm_description'), 'launch', '_robot_description.launch.py'])),
|
PythonLaunchDescriptionSource(PathJoinSubstitution([FindPackageShare('custom_xarm_description'), 'launch', '_robot_description.launch.py'])),
|
||||||
launch_arguments={
|
launch_arguments={
|
||||||
'prefix': prefix,
|
'prefix': prefix,
|
||||||
'hw_ns': hw_ns,
|
'hw_ns': hw_ns,
|
||||||
@@ -105,12 +109,12 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
|
|
||||||
# robot_description_parameters
|
# robot_description_parameters
|
||||||
# xarm_moveit_config/launch/lib/robot_moveit_config_lib.py
|
# xarm_moveit_config/launch/lib/robot_moveit_config_lib.py
|
||||||
moveit_config_package_name = 'xarm_moveit_config'
|
moveit_config_package_name = 'custom_xarm_moveit_config'
|
||||||
mod = load_python_launch_file_as_module(os.path.join(get_package_share_directory(moveit_config_package_name), 'launch', 'lib', 'robot_moveit_config_lib.py'))
|
mod = load_python_launch_file_as_module(os.path.join(get_package_share_directory(moveit_config_package_name), 'launch', 'lib', 'robot_moveit_config_lib.py'))
|
||||||
get_xarm_robot_description_parameters = getattr(mod, 'get_xarm_robot_description_parameters')
|
get_xarm_robot_description_parameters = getattr(mod, 'get_xarm_robot_description_parameters')
|
||||||
robot_description_parameters = get_xarm_robot_description_parameters(
|
robot_description_parameters = get_xarm_robot_description_parameters(
|
||||||
xacro_urdf_file=PathJoinSubstitution([FindPackageShare('xarm_description'), 'urdf', 'xarm_device.urdf.xacro']),
|
xacro_urdf_file=PathJoinSubstitution([FindPackageShare('custom_xarm_description'), 'urdf', 'xarm_device.urdf.xacro']),
|
||||||
xacro_srdf_file=PathJoinSubstitution([FindPackageShare('xarm_moveit_config'), 'srdf', 'xarm.srdf.xacro']),
|
xacro_srdf_file=PathJoinSubstitution([FindPackageShare('custom_xarm_moveit_config'), 'srdf', 'xarm.srdf.xacro']),
|
||||||
urdf_arguments={
|
urdf_arguments={
|
||||||
'prefix': prefix,
|
'prefix': prefix,
|
||||||
'hw_ns': hw_ns.perform(context).strip('/'),
|
'hw_ns': hw_ns.perform(context).strip('/'),
|
||||||
@@ -155,10 +159,16 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
kinematics_yaml = robot_description_parameters['robot_description_kinematics']
|
kinematics_yaml = robot_description_parameters['robot_description_kinematics']
|
||||||
joint_limits_yaml = robot_description_parameters.get('robot_description_planning', None)
|
joint_limits_yaml = robot_description_parameters.get('robot_description_planning', None)
|
||||||
|
|
||||||
|
robotcontroller_config = config.perform(context)
|
||||||
|
with open(robotcontroller_config, 'r') as f:
|
||||||
|
lite6_config = yaml.safe_load(f)
|
||||||
|
print(f'Loaded configuration: {lite6_config}')
|
||||||
|
robot_description_parameters.update(lite6_config['/robot_controller']['ros__parameters'])
|
||||||
|
|
||||||
# FIX acceleration limits
|
# FIX acceleration limits
|
||||||
for i in range(1,7):
|
#for i in range(1,7):
|
||||||
joint_limits_yaml['joint_limits']['joint{}'.format(i)]['has_acceleration_limits'] = True
|
# joint_limits_yaml['joint_limits']['joint{}'.format(i)]['has_acceleration_limits'] = True
|
||||||
joint_limits_yaml['joint_limits']['joint{}'.format(i)]['max_acceleration'] = 1.0
|
# joint_limits_yaml['joint_limits']['joint{}'.format(i)]['max_acceleration'] = 1.0
|
||||||
|
|
||||||
if add_gripper.perform(context) in ('True', 'true'):
|
if add_gripper.perform(context) in ('True', 'true'):
|
||||||
gripper_controllers_yaml = load_yaml(moveit_config_package_name, 'config', '{}_gripper'.format(robot_type.perform(context)), '{}.yaml'.format(controllers_name.perform(context)))
|
gripper_controllers_yaml = load_yaml(moveit_config_package_name, 'config', '{}_gripper'.format(robot_type.perform(context)), '{}.yaml'.format(controllers_name.perform(context)))
|
||||||
@@ -182,11 +192,8 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
kinematics_yaml=kinematics_yaml, joint_limits_yaml=joint_limits_yaml,
|
kinematics_yaml=kinematics_yaml, joint_limits_yaml=joint_limits_yaml,
|
||||||
prefix=prefix.perform(context))
|
prefix=prefix.perform(context))
|
||||||
|
|
||||||
robot_description_parameters['cartesian_limits'] = {}
|
#cartesian_limits = load_yaml(moveit_config_package_name, 'config', xarm_type, 'cartesian_limits.yaml')
|
||||||
robot_description_parameters['cartesian_limits']['max_trans_vel'] = 1
|
#robot_description_parameters['robot_description_planning']['cartesian_limits'] = cartesian_limits['cartesian_limits']
|
||||||
robot_description_parameters['cartesian_limits']['max_trans_acc'] = 2.25
|
|
||||||
robot_description_parameters['cartesian_limits']['max_trans_dec'] = -5
|
|
||||||
robot_description_parameters['cartesian_limits']['max_rot_vel'] = 1.57
|
|
||||||
|
|
||||||
# Planning Configuration
|
# Planning Configuration
|
||||||
ompl_planning_pipeline_config = {
|
ompl_planning_pipeline_config = {
|
||||||
@@ -236,15 +243,8 @@ def launch_setup(context, *args, **kwargs):
|
|||||||
'publish_geometry_updates': True,
|
'publish_geometry_updates': True,
|
||||||
'publish_state_updates': True,
|
'publish_state_updates': True,
|
||||||
'publish_transforms_updates': True,
|
'publish_transforms_updates': True,
|
||||||
# "planning_scene_monitor_options": {
|
'publish_robot_description': True,
|
||||||
# "name": "planning_scene_monitor",
|
'publish_robot_description_semantic' :True,
|
||||||
# "robot_description": "robot_description",
|
|
||||||
# "joint_state_topic": "/joint_states",
|
|
||||||
# "attached_collision_object_topic": "/move_group/planning_scene_monitor",
|
|
||||||
# "publish_planning_scene_topic": "/move_group/publish_planning_scene",
|
|
||||||
# "monitored_planning_scene_topic": "/move_group/monitored_planning_scene",
|
|
||||||
# "wait_for_initial_state_timeout": 10.0,
|
|
||||||
# },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Start the actual move_group node/action server
|
# Start the actual move_group node/action server
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
<!-- <depend>robot_controller</depend> -->
|
<!-- <depend>robot_controller</depend> -->
|
||||||
<depend>moveit</depend>
|
<depend>moveit</depend>
|
||||||
<depend>moveit_msgs</depend>
|
<depend>moveit_msgs</depend>
|
||||||
|
<depend>xarm_msgs</depend>
|
||||||
|
<depend>xarm_api</depend>
|
||||||
<depend>geometry_msgs</depend>
|
<depend>geometry_msgs</depend>
|
||||||
<depend>moveit_ros_planning_interface</depend>
|
<depend>moveit_ros_planning_interface</depend>
|
||||||
<depend>tf2_ros</depend>
|
<depend>tf2_ros</depend>
|
||||||
|
|||||||
131
src/lite6_controller/src/lite6_calibration.cpp
Normal file
131
src/lite6_controller/src/lite6_calibration.cpp
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
#include <signal.h>
|
||||||
|
#include <chrono>
|
||||||
|
#include <rclcpp/rclcpp.hpp>
|
||||||
|
#include <xarm_api/xarm_ros_client.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// MoveIt
|
||||||
|
#include <moveit/robot_model_loader/robot_model_loader.h>
|
||||||
|
#include <moveit/robot_model/robot_model.h>
|
||||||
|
#include <moveit/robot_state/robot_state.h>
|
||||||
|
|
||||||
|
|
||||||
|
const std::string MOVE_GROUP = "lite6";
|
||||||
|
|
||||||
|
std::shared_ptr<rclcpp::Node> node;
|
||||||
|
|
||||||
|
void exit_sig_handler(int signum)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "[lite6_calibration] Ctrl-C caught, exit process...\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait()
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
std::cout << "Press a key to continue...";
|
||||||
|
} while (std::cin.get() != '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void println(std::string s)
|
||||||
|
{
|
||||||
|
std::cout << s << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_joints(std::vector<float> jnts)
|
||||||
|
{
|
||||||
|
std::string out = "";
|
||||||
|
out = out + "{ ";
|
||||||
|
for (auto i : jnts)
|
||||||
|
out = out + std::to_string(i) + ", ";
|
||||||
|
out = out.substr(0, out.size()-2); //remove trailing comma
|
||||||
|
out = out + " }";
|
||||||
|
std::cout << out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
rclcpp::init(argc, argv);
|
||||||
|
std::string hw_ns = "ufactory";
|
||||||
|
node = rclcpp::Node::make_shared("lite6_calibration");
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
signal(SIGINT, exit_sig_handler);
|
||||||
|
|
||||||
|
xarm_api::XArmROSClient client;
|
||||||
|
client.init(node, hw_ns);
|
||||||
|
client.motion_enable(true);
|
||||||
|
|
||||||
|
println("Setting xArm lite6 to free-drive mode. Attach pen and touch the drawing surface. (You can also skip this if you do not want to measure Z)");
|
||||||
|
client.set_mode(2);
|
||||||
|
client.set_state(0);
|
||||||
|
//rclcpp::sleep_for(std::chrono::seconds(20));
|
||||||
|
wait();
|
||||||
|
//client.set_mode(0);
|
||||||
|
//client.set_state(0);
|
||||||
|
//rclcpp::sleep_for(std::chrono::seconds(2));
|
||||||
|
|
||||||
|
client.set_mode(0);
|
||||||
|
client.set_state(0);
|
||||||
|
rclcpp::sleep_for(std::chrono::seconds(2));
|
||||||
|
|
||||||
|
//std::vector<float> jnt_drawing_pose = { -0.975004, 0.0734182, 0.443928, 3.14102, -0.370552, -0.85577, 0 };
|
||||||
|
std::vector<float> jnt_drawing_pose = { -0.975008, 0.00889134, 0.453255, 3.1414, -0.444295, -0.85692, 0 } ;
|
||||||
|
|
||||||
|
std::vector<float> jnt_pose = { 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
client.get_servo_angle(jnt_pose);
|
||||||
|
|
||||||
|
print_joints(jnt_pose);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//client.set_servo_angle_j(jnt_drawing_pose, 1, 1, 100);
|
||||||
|
//rclcpp::sleep_for(std::chrono::seconds(5));
|
||||||
|
|
||||||
|
|
||||||
|
// Compute position of pen from joint state
|
||||||
|
robot_model_loader::RobotModelLoader robot_model_loader(node);
|
||||||
|
const moveit::core::RobotModelPtr& kinematic_model = robot_model_loader.getModel();
|
||||||
|
moveit::core::RobotStatePtr kinematic_state(new moveit::core::RobotState(kinematic_model));
|
||||||
|
const moveit::core::JointModelGroup* joint_model_group = kinematic_model->getJointModelGroup(MOVE_GROUP);
|
||||||
|
std::string ee_link = "pen_link";
|
||||||
|
|
||||||
|
std::vector<double> jnts;
|
||||||
|
for (auto j : jnt_pose)
|
||||||
|
jnts.push_back(j);
|
||||||
|
|
||||||
|
jnts.resize(joint_model_group->getVariableNames().size());
|
||||||
|
kinematic_state->setJointGroupPositions(joint_model_group, jnts);
|
||||||
|
|
||||||
|
// from tutorial https://ros-planning.github.io/moveit_tutorials/doc/robot_model_and_robot_state/robot_model_and_robot_state_tutorial.html
|
||||||
|
// https://github.com/ros-planning/moveit_tutorials/blob/master/doc/robot_model_and_robot_state/src/robot_model_and_robot_state_tutorial.cpp
|
||||||
|
//robot_model_loader::RobotModelLoader robot_model_loader(node, "robot_description");
|
||||||
|
|
||||||
|
kinematic_state->setJointGroupPositions(joint_model_group, jnts);
|
||||||
|
// https://mycourses.aalto.fi/pluginfile.php/1433193/mod_resource/content/2/Intro_to_ROS_Eigen.pdf
|
||||||
|
const Eigen::Isometry3d& end_effector_state = kinematic_state->getGlobalLinkTransform(ee_link);
|
||||||
|
|
||||||
|
auto x = std::to_string(end_effector_state.translation().x());
|
||||||
|
auto y = std::to_string(end_effector_state.translation().y());
|
||||||
|
auto z = std::to_string(end_effector_state.translation().z());
|
||||||
|
//println("x for '" + ee_link + "': " + x);
|
||||||
|
//println("y for '" + ee_link + "': " + y);
|
||||||
|
println("z-offset value for '" + ee_link + "' (use this value for the current pen): " + z);
|
||||||
|
|
||||||
|
|
||||||
|
println("WARNING. Moving to start drawing pose. Press ctrl-c to cancel");
|
||||||
|
wait();
|
||||||
|
client.set_servo_angle(jnt_drawing_pose, 1, 1, 1, true, 100, -1);
|
||||||
|
|
||||||
|
|
||||||
|
client.set_mode(0);
|
||||||
|
client.set_state(0);
|
||||||
|
|
||||||
|
rclcpp::shutdown();
|
||||||
|
|
||||||
|
println("Done, ignore any errors after this. Restart lite6_controller after I exit.");
|
||||||
|
wait();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -47,15 +47,6 @@ const std::string MOVE_GROUP = "lite6";
|
|||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
// MOTION PLANNING API
|
|
||||||
// https://github.com/ros-planning/moveit2_tutorials/blob/humble/doc/examples/motion_planning_api/src/motion_planning_api_tutorial.cpp
|
|
||||||
// https://moveit.picknik.ai/humble/doc/examples/motion_planning_api/motion_planning_api_tutorial.html
|
|
||||||
// https://github.com/ros-planning/moveit2/blob/main/moveit_planners/pilz_industrial_motion_planner/src/move_group_sequence_service.cpp
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// USE
|
|
||||||
// https://industrial-training-master.readthedocs.io/en/foxy/_source/session4/ros2/0-Motion-Planning-CPP.html
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for xArm Lite6, implementing RobotController
|
* Controller for xArm Lite6, implementing RobotController
|
||||||
*/
|
*/
|
||||||
@@ -89,20 +80,9 @@ public:
|
|||||||
float xlim_upper = 0.305;
|
float xlim_upper = 0.305;
|
||||||
float ylim_lower = -0.1475;
|
float ylim_lower = -0.1475;
|
||||||
float ylim_upper = 0.1475;
|
float ylim_upper = 0.1475;
|
||||||
float zlim_lower = 0.210;
|
float zlim_lower = 0.141087;
|
||||||
float zlim_upper = 0.218;
|
float zlim_upper = zlim_lower + 0.01;
|
||||||
|
|
||||||
//bool moved = false;
|
|
||||||
//
|
|
||||||
// TODO get pilz working
|
|
||||||
//std::unique_ptr<pilz_industrial_motion_planner::CommandListManager> command_list_manager_;
|
|
||||||
// command_list_manager_ = std::make_unique<pilz_industrial_motion_planner::CommandListManager>(this->move_group.getNodeHandle(), this->move_group.getRobotModel());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CommandListManager, used to plan MotionSequenceRequest
|
|
||||||
*/
|
|
||||||
//pilz_industrial_motion_planner::CommandListManager command_list_manager;
|
|
||||||
//pilz_industrial_motion_planner::CommandListManager command_list_manager(*std::shared_ptr<rclcpp::Node>(std::move(this)), this->move_group.getRobotModel());
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@@ -110,24 +90,29 @@ public:
|
|||||||
Lite6Controller(const rclcpp::NodeOptions & options = rclcpp::NodeOptions())
|
Lite6Controller(const rclcpp::NodeOptions & options = rclcpp::NodeOptions())
|
||||||
: RobotController(options),
|
: RobotController(options),
|
||||||
move_group(std::shared_ptr<rclcpp::Node>(std::move(this)), MOVE_GROUP)
|
move_group(std::shared_ptr<rclcpp::Node>(std::move(this)), MOVE_GROUP)
|
||||||
//moveit_cpp_(std::shared_ptr<rclcpp::Node>(std::move(this))),
|
|
||||||
//planning_component_(MOVE_GROUP, moveit_cpp_),
|
|
||||||
//command_list_manager(std::shared_ptr<rclcpp::Node>(std::move(this)), this->move_group.getRobotModel())
|
|
||||||
{
|
{
|
||||||
|
// Declare parameters
|
||||||
|
this->declare_parameter("lite6_x_limit_lower", 0.1);
|
||||||
|
this->declare_parameter("lite6_x_limit_upper", 0.305);
|
||||||
|
this->declare_parameter("lite6_y_limit_lower", -0.1475);
|
||||||
|
this->declare_parameter("lite6_y_limit_upper", 0.1475);
|
||||||
|
this->declare_parameter("lite6_z_offset", 0.141087);
|
||||||
|
this->declare_parameter("lite6_z_lift_amount", 0.01);
|
||||||
|
this->declare_parameter("lite6_max_velocity_scaling_factor", 1.0);
|
||||||
|
this->declare_parameter("lite6_max_acceleration_scaling_factor", 0.6);
|
||||||
|
this->declare_parameter("lite6_blend_radius", 0.0);
|
||||||
|
|
||||||
|
xlim_lower = this->get_parameter("lite6_x_limit_lower").as_double();
|
||||||
|
xlim_upper = this->get_parameter("lite6_x_limit_upper").as_double();
|
||||||
|
ylim_lower = this->get_parameter("lite6_y_limit_lower").as_double();
|
||||||
|
ylim_upper = this->get_parameter("lite6_y_limit_upper").as_double();
|
||||||
|
zlim_lower = this->get_parameter("lite6_z_offset").as_double();
|
||||||
|
zlim_upper = zlim_lower + this->get_parameter("lite6_z_lift_amount").as_double();
|
||||||
|
|
||||||
//command_list_manager = new pilz_industrial_motion_planner::CommandListManager(this->move_group.getNodeHandle(), this->move_group.getRobotModel());
|
|
||||||
//command_list_manager = new pilz_industrial_motion_planner::CommandListManager(std::shared_ptr<rclcpp::Node>(std::move(this)), this->move_group.getRobotModel());
|
|
||||||
// Use upper joint velocity and acceleration limits
|
|
||||||
this->move_group.setMaxAccelerationScalingFactor(1.0);
|
this->move_group.setMaxAccelerationScalingFactor(1.0);
|
||||||
|
this->move_group.setMaxVelocityScalingFactor(1.0);
|
||||||
|
//this->move_group.setMaxVelocityScalingFactor(0.8);
|
||||||
|
|
||||||
//setting this lower seems to improve overall time and prevents robot from moving too fast
|
|
||||||
//this->move_group.setMaxVelocityScalingFactor(1.0);
|
|
||||||
this->move_group.setMaxVelocityScalingFactor(0.8);
|
|
||||||
|
|
||||||
// Subscribe to target pose
|
|
||||||
//target_pose_sub_ = this->create_subscription<geometry_msgs::msg::PoseStamped>("/target_pose", rclcpp::QoS(1), std::bind(&MoveItFollowTarget::target_pose_callback, this, std::placeholders::_1));
|
|
||||||
|
|
||||||
//
|
|
||||||
trajectory_timer_ = this->create_wall_timer(
|
trajectory_timer_ = this->create_wall_timer(
|
||||||
10ms, std::bind(&Lite6Controller::executeTrajectoryFromQueue, this));
|
10ms, std::bind(&Lite6Controller::executeTrajectoryFromQueue, this));
|
||||||
|
|
||||||
@@ -135,18 +120,10 @@ public:
|
|||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
//moveit_cpp_ = std::make_shared<moveit_cpp::MoveItCpp>(move_group.getNodeHandle());
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//moveit_cpp_ = std::make_shared<moveit_cpp::MoveItCpp>(this->shared_from_this());
|
|
||||||
//moveit_cpp_ = std::make_shared<moveit_cpp::MoveItCpp>(move_group.getNodeHandle());
|
|
||||||
//planning_component_ = std::make_shared<moveit_cpp::PlanningComponent>(MOVE_GROUP, moveit_cpp_);
|
|
||||||
//
|
|
||||||
|
|
||||||
planning_scene_monitor_ = std::make_shared<planning_scene_monitor::PlanningSceneMonitor>(this->shared_from_this(),
|
planning_scene_monitor_ = std::make_shared<planning_scene_monitor::PlanningSceneMonitor>(this->shared_from_this(),
|
||||||
"robot_description");
|
"robot_description");
|
||||||
//RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Getting initial robot state");
|
|
||||||
//move_group.startStateMonitor(5);
|
|
||||||
|
|
||||||
this->sequence_client_ =
|
this->sequence_client_ =
|
||||||
this->create_client<moveit_msgs::srv::GetMotionSequence>("plan_sequence_path");
|
this->create_client<moveit_msgs::srv::GetMotionSequence>("plan_sequence_path");
|
||||||
@@ -217,11 +194,12 @@ public:
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
moveit_msgs::msg::MotionSequenceRequest createMotionSequenceRequest(const std::vector<geometry_msgs::msg::PoseStamped> *path)
|
moveit_msgs::msg::MotionSequenceRequest createMotionSequenceRequest(const std::vector<geometry_msgs::msg::PoseStamped> *path, std::string planner_id)
|
||||||
{
|
{
|
||||||
moveit_msgs::msg::MotionSequenceRequest msr = moveit_msgs::msg::MotionSequenceRequest();
|
moveit_msgs::msg::MotionSequenceRequest msr = moveit_msgs::msg::MotionSequenceRequest();
|
||||||
//waypoints.push_back(move_group.getCurrentPose().pose);
|
//waypoints.push_back(move_group.getCurrentPose().pose);
|
||||||
std::string ee_link = move_group.getLinkNames().back();
|
//std::string ee_link = move_group.getLinkNames().back();
|
||||||
|
std::string ee_link = "pen_link";
|
||||||
RCLCPP_INFO(this->get_logger(), "Got ee_link: %s", ee_link.c_str());
|
RCLCPP_INFO(this->get_logger(), "Got ee_link: %s", ee_link.c_str());
|
||||||
geometry_msgs::msg::Point previous_point;
|
geometry_msgs::msg::Point previous_point;
|
||||||
//previous_point.point.x = -1.0;
|
//previous_point.point.x = -1.0;
|
||||||
@@ -233,13 +211,17 @@ public:
|
|||||||
moveit_msgs::msg::MotionSequenceItem msi = moveit_msgs::msg::MotionSequenceItem();
|
moveit_msgs::msg::MotionSequenceItem msi = moveit_msgs::msg::MotionSequenceItem();
|
||||||
|
|
||||||
planning_interface::MotionPlanRequest mpr = planning_interface::MotionPlanRequest();
|
planning_interface::MotionPlanRequest mpr = planning_interface::MotionPlanRequest();
|
||||||
mpr.planner_id = "PTP";
|
mpr.planner_id = planner_id;
|
||||||
|
//mpr.planner_id = "PTP";
|
||||||
//mpr.planner_id = "LIN";
|
//mpr.planner_id = "LIN";
|
||||||
mpr.group_name = move_group.getName();
|
mpr.group_name = move_group.getName();
|
||||||
mpr.max_velocity_scaling_factor = 1.0;
|
//mpr.max_velocity_scaling_factor = 1.0;
|
||||||
mpr.max_acceleration_scaling_factor = 0.98;
|
mpr.max_velocity_scaling_factor = this->get_parameter("lite6_max_velocity_scaling_factor").as_double();
|
||||||
mpr.allowed_planning_time = 10;
|
mpr.max_acceleration_scaling_factor = this->get_parameter("lite6_max_acceleration_scaling_factor").as_double();
|
||||||
mpr.max_cartesian_speed = 2; // m/s
|
|
||||||
|
//mpr.max_acceleration_scaling_factor = 0.1;
|
||||||
|
mpr.allowed_planning_time = 20;
|
||||||
|
//mpr.max_cartesian_speed = 2; // m/s
|
||||||
//mpr.goal_constraints.position_constraints.header.frame_id = "world";
|
//mpr.goal_constraints.position_constraints.header.frame_id = "world";
|
||||||
|
|
||||||
// A tolerance of 0.01 m is specified in position
|
// A tolerance of 0.01 m is specified in position
|
||||||
@@ -268,9 +250,7 @@ public:
|
|||||||
mpr.goal_constraints.push_back(pose_goal);
|
mpr.goal_constraints.push_back(pose_goal);
|
||||||
|
|
||||||
msi.req = mpr;
|
msi.req = mpr;
|
||||||
//msi.blend_radius = 6e-7; //TODO make configurable
|
msi.blend_radius = this->get_parameter("lite6_blend_radius").as_double();
|
||||||
//msi.blend_radius = 0.000001; //TODO make configurable
|
|
||||||
msi.blend_radius = 0.0; //TODO make configurable
|
|
||||||
if (coincidentPoints(&pose.pose.position, &previous_point, msi.blend_radius + 1e-5))
|
if (coincidentPoints(&pose.pose.position, &previous_point, msi.blend_radius + 1e-5))
|
||||||
{
|
{
|
||||||
RCLCPP_ERROR(this->get_logger(), "Detected coincident points, setting blend radius to 0.0");
|
RCLCPP_ERROR(this->get_logger(), "Detected coincident points, setting blend radius to 0.0");
|
||||||
@@ -286,6 +266,7 @@ public:
|
|||||||
msr.items.push_back(msi);
|
msr.items.push_back(msi);
|
||||||
}
|
}
|
||||||
msr.items.back().blend_radius = 0.0; // Last element blend must be 0
|
msr.items.back().blend_radius = 0.0; // Last element blend must be 0
|
||||||
|
|
||||||
moveit_msgs::msg::RobotState state_msg;
|
moveit_msgs::msg::RobotState state_msg;
|
||||||
if (move_group_state == NULL)
|
if (move_group_state == NULL)
|
||||||
{
|
{
|
||||||
@@ -297,6 +278,11 @@ public:
|
|||||||
return msr;
|
return msr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
moveit_msgs::msg::MotionSequenceRequest createMotionSequenceRequest(const std::vector<geometry_msgs::msg::PoseStamped> *path)
|
||||||
|
{
|
||||||
|
return createMotionSequenceRequest(path, "LIN");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -400,8 +386,17 @@ public:
|
|||||||
|
|
||||||
void executeTrajectoryFromQueue()
|
void executeTrajectoryFromQueue()
|
||||||
{
|
{
|
||||||
if (busy || trajectory_queue.empty())
|
if (trajectory_queue.empty())
|
||||||
|
{
|
||||||
|
if (busy)
|
||||||
|
return;
|
||||||
|
|
||||||
|
busy = true;
|
||||||
|
//RCLCPP_INFO(this->get_logger(), "Getting robot state");
|
||||||
|
//move_group_state = move_group.getCurrentState(10);
|
||||||
|
busy = false;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
busy = true;
|
busy = true;
|
||||||
RCLCPP_INFO(this->get_logger(), "Executing next trajectory from queue");
|
RCLCPP_INFO(this->get_logger(), "Executing next trajectory from queue");
|
||||||
move_group.execute(trajectory_queue.front());
|
move_group.execute(trajectory_queue.front());
|
||||||
@@ -409,6 +404,103 @@ public:
|
|||||||
busy = false;
|
busy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
moveit_msgs::msg::RobotTrajectory sendRequest(moveit_msgs::msg::MotionSequenceRequest msr)
|
||||||
|
{
|
||||||
|
auto req = std::make_shared<moveit_msgs::srv::GetMotionSequence::Request>();
|
||||||
|
req->request = msr;
|
||||||
|
RCLCPP_INFO(this->get_logger(), "Sending request to sequence service");
|
||||||
|
auto res = sequence_client_->async_send_request(req);
|
||||||
|
|
||||||
|
auto ts = res.get()->response.planned_trajectories;
|
||||||
|
|
||||||
|
// Set move_group_state to the last state of planned trajectory (planning of next trajectory starts there)
|
||||||
|
|
||||||
|
if (ts.empty())
|
||||||
|
{
|
||||||
|
moveit_msgs::msg::RobotTrajectory t;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return ts[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMoveGroupState(moveit_msgs::msg::RobotTrajectory t)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (t.joint_trajectory.points.empty())
|
||||||
|
{
|
||||||
|
RCLCPP_ERROR(this->get_logger(), "TRAJECTORY IS EMPTY");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
robot_trajectory::RobotTrajectory rt(move_group.getRobotModel());
|
||||||
|
rt.setRobotTrajectoryMsg(*move_group_state, t);
|
||||||
|
move_group_state = rt.getLastWayPointPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pathToTrajectory(const std::vector<geometry_msgs::msg::PoseStamped> *path, std::vector<moveit_msgs::msg::RobotTrajectory> *ts)
|
||||||
|
{
|
||||||
|
std::vector<geometry_msgs::msg::PoseStamped> penup = {};
|
||||||
|
std::vector<geometry_msgs::msg::PoseStamped> tail = {};
|
||||||
|
bool up = true;
|
||||||
|
if (!path)
|
||||||
|
{
|
||||||
|
RCLCPP_ERROR(this->get_logger(), "Received null pointer for path");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto p : *path)
|
||||||
|
{
|
||||||
|
if (p.pose.position.z > 0)
|
||||||
|
up = false;
|
||||||
|
if (up)
|
||||||
|
//penup->push_back(p);
|
||||||
|
penup.push_back(p);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
up = false;
|
||||||
|
//tail->push_back(p);
|
||||||
|
tail.push_back(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!penup.empty())
|
||||||
|
{
|
||||||
|
auto msr = createMotionSequenceRequest(&penup, "PTP");
|
||||||
|
RCLCPP_ERROR(this->get_logger(), "Created MSR for penup");
|
||||||
|
if (msr.items.empty())
|
||||||
|
{
|
||||||
|
RCLCPP_ERROR(this->get_logger(), "MSR EMPTY");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ts->push_back(sendRequest(msr));
|
||||||
|
//planAndLogOffset(&penup);
|
||||||
|
setMoveGroupState(ts->back());
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RCLCPP_ERROR(this->get_logger(), "Penup path is empty, all motions will be LIN");
|
||||||
|
}
|
||||||
|
if (!tail.empty())
|
||||||
|
{
|
||||||
|
auto msr = createMotionSequenceRequest(&tail, "LIN");
|
||||||
|
RCLCPP_ERROR(this->get_logger(), "Created MSR for tail");
|
||||||
|
if (msr.items.empty())
|
||||||
|
{
|
||||||
|
RCLCPP_ERROR(this->get_logger(), "MSR EMPTY");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ts->push_back(sendRequest(msr));
|
||||||
|
//planAndLogOffset(&tail);
|
||||||
|
setMoveGroupState(ts->back());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RCLCPP_ERROR(this->get_logger(), "Path was empty, no trajectories created");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback that executes path on robot
|
* Callback that executes path on robot
|
||||||
*/
|
*/
|
||||||
@@ -421,37 +513,33 @@ public:
|
|||||||
auto feedback = std::make_shared<robot_interfaces::action::ExecuteMotion::Feedback>();
|
auto feedback = std::make_shared<robot_interfaces::action::ExecuteMotion::Feedback>();
|
||||||
auto result = std::make_shared<robot_interfaces::action::ExecuteMotion::Result>();
|
auto result = std::make_shared<robot_interfaces::action::ExecuteMotion::Result>();
|
||||||
|
|
||||||
auto msr = createMotionSequenceRequest(&goal->motion.path);
|
std::vector<moveit_msgs::msg::RobotTrajectory> ts;
|
||||||
RCLCPP_INFO(this->get_logger(), "Created MSR");
|
pathToTrajectory(&goal->motion.path, &ts);
|
||||||
|
|
||||||
//planAndLogOffset(&goal->motion.path);
|
long unsigned int n = 0;
|
||||||
|
|
||||||
|
RCLCPP_INFO(this->get_logger(), "Got %ld trajectories", ts.size());
|
||||||
|
for (auto t : ts)
|
||||||
|
{
|
||||||
|
RCLCPP_INFO(this->get_logger(), "Adding result to motion queue");
|
||||||
|
if (t.joint_trajectory.points.empty())
|
||||||
|
{
|
||||||
|
RCLCPP_ERROR(this->get_logger(), "TRAJECTORY IS EMPTY");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
trajectory_queue.push(t);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
RCLCPP_INFO(this->get_logger(), "Creating req");
|
|
||||||
auto req = std::make_shared<moveit_msgs::srv::GetMotionSequence::Request>();
|
|
||||||
RCLCPP_INFO(this->get_logger(), "Setting msr request");
|
|
||||||
req->request = msr;
|
|
||||||
RCLCPP_INFO(this->get_logger(), "Sending request to sequence service");
|
|
||||||
auto res = sequence_client_->async_send_request(req);
|
|
||||||
RCLCPP_INFO(this->get_logger(), "Waiting for result");
|
|
||||||
auto ts = res.get()->response.planned_trajectories;
|
|
||||||
std::string status = "";
|
std::string status = "";
|
||||||
if (ts.size() > 0)
|
if (n == ts.size())
|
||||||
{
|
{
|
||||||
status = "success";
|
status = "success";
|
||||||
RCLCPP_INFO(this->get_logger(), "Got %ld trajectories", ts.size());
|
|
||||||
RCLCPP_INFO(this->get_logger(), "Adding result to motion queue");
|
|
||||||
|
|
||||||
trajectory_queue.push(ts[0]);
|
|
||||||
|
|
||||||
// Set move_group_state to the last state of planned trajectory (planning of next trajectory starts there)
|
|
||||||
robot_trajectory::RobotTrajectory rt(move_group.getRobotModel());
|
|
||||||
rt.setRobotTrajectoryMsg(*move_group_state, ts[0]);
|
|
||||||
move_group_state = rt.getLastWayPointPtr();
|
|
||||||
|
|
||||||
status = status + "," + pointsToString(&goal->motion.path,0,0,0);
|
status = status + "," + pointsToString(&goal->motion.path,0,0,0);
|
||||||
appendLineToFile("OUTPUT.csv", status);
|
appendLineToFile("OUTPUT.csv", status);
|
||||||
|
|
||||||
result->result = "success";
|
result->result = "success";
|
||||||
|
|
||||||
goal_handle->succeed(result);
|
goal_handle->succeed(result);
|
||||||
RCLCPP_INFO(this->get_logger(), "Goal succeeded");
|
RCLCPP_INFO(this->get_logger(), "Goal succeeded");
|
||||||
return;
|
return;
|
||||||
|
|||||||
111
src/lite6_controller/src/lite6_trajectory_executor.cpp
Normal file
111
src/lite6_controller/src/lite6_trajectory_executor.cpp
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <rclcpp/rclcpp.hpp>
|
||||||
|
#include <robot_controller/robot_controller.hpp>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <geometry_msgs/msg/pose_stamped.hpp>
|
||||||
|
#include <geometry_msgs/msg/pose.hpp>
|
||||||
|
#include <moveit_msgs/msg/collision_object.hpp>
|
||||||
|
|
||||||
|
//#include <moveit/planning_interface/planning_interface.h>
|
||||||
|
//#include <moveit/planning_interface/planning_response.h>
|
||||||
|
//#include <moveit/kinematic_constraints/kinematic_constraint.h>
|
||||||
|
#include <moveit/kinematic_constraints/utils.h>
|
||||||
|
#include <moveit/move_group_interface/move_group_interface.h>
|
||||||
|
|
||||||
|
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
|
||||||
|
#include <tf2_eigen/tf2_eigen.hpp>
|
||||||
|
|
||||||
|
#include <moveit/planning_scene_interface/planning_scene_interface.h>
|
||||||
|
#include <moveit/move_group_interface/move_group_interface.h>
|
||||||
|
#include <moveit/common_planning_interface_objects/common_objects.h>
|
||||||
|
#include <moveit/planning_scene_monitor/planning_scene_monitor.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <moveit_msgs/msg/constraints.hpp>
|
||||||
|
#include <moveit_msgs/msg/robot_trajectory.hpp>
|
||||||
|
#include <moveit_msgs/msg/motion_plan_request.hpp>
|
||||||
|
#include <moveit_msgs/msg/motion_sequence_request.hpp>
|
||||||
|
#include <moveit_msgs/msg/motion_sequence_item.hpp>
|
||||||
|
#include <moveit_msgs/srv/get_motion_sequence.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
#include <moveit/moveit_cpp/moveit_cpp.h>
|
||||||
|
#include <moveit/moveit_cpp/planning_component.h>
|
||||||
|
|
||||||
|
#include <moveit/robot_trajectory/robot_trajectory.h>
|
||||||
|
|
||||||
|
#include <pilz_industrial_motion_planner/command_list_manager.h>
|
||||||
|
|
||||||
|
const std::string MOVE_GROUP = "lite6";
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
class TrajectoryExecutor : public rclcpp::Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//trajectory_pub = this->create_publisher<moveit_msgs::msg::RobotTrajectory>("lite6_trajectory", 10);
|
||||||
|
rclcpp::Subscription<moveit_msgs::msg::RobotTrajectory>::SharedPtr subscription;
|
||||||
|
moveit::planning_interface::MoveGroupInterface move_group;
|
||||||
|
|
||||||
|
rclcpp::TimerBase::SharedPtr trajectory_timer_;
|
||||||
|
std::queue<moveit_msgs::msg::RobotTrajectory> trajectory_queue;
|
||||||
|
bool busy = false;
|
||||||
|
|
||||||
|
TrajectoryExecutor(const rclcpp::NodeOptions & options = rclcpp::NodeOptions())
|
||||||
|
: Node("lite6_trajectory_executor",options),
|
||||||
|
move_group(std::shared_ptr<rclcpp::Node>(std::move(this)), MOVE_GROUP)
|
||||||
|
{
|
||||||
|
subscription = this->create_subscription<moveit_msgs::msg::RobotTrajectory>(
|
||||||
|
"lite6_trajectory", 100, std::bind(&TrajectoryExecutor::trajectory_callback, this, std::placeholders::_1));
|
||||||
|
|
||||||
|
trajectory_timer_ = this->create_wall_timer(
|
||||||
|
10ms, std::bind(&TrajectoryExecutor::executeTrajectoryFromQueue, this));
|
||||||
|
}
|
||||||
|
void trajectory_callback(const moveit_msgs::msg::RobotTrajectory msg)
|
||||||
|
{
|
||||||
|
RCLCPP_INFO(this->get_logger(), "Received trajectory, adding to queue");
|
||||||
|
//move_group.execute(msg);
|
||||||
|
trajectory_queue.push(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void executeTrajectoryFromQueue()
|
||||||
|
{
|
||||||
|
if (busy || trajectory_queue.empty())
|
||||||
|
return;
|
||||||
|
busy = true;
|
||||||
|
RCLCPP_INFO(this->get_logger(), "Executing next trajectory from queue");
|
||||||
|
move_group.execute(trajectory_queue.front());
|
||||||
|
trajectory_queue.pop();
|
||||||
|
busy = false;
|
||||||
|
RCLCPP_INFO(this->get_logger(), "Finished executing trajectory");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts lite6_controller
|
||||||
|
*/
|
||||||
|
int main(int argc, char ** argv)
|
||||||
|
{
|
||||||
|
rclcpp::init(argc, argv);
|
||||||
|
|
||||||
|
auto trajectory_executor = std::make_shared<TrajectoryExecutor>();
|
||||||
|
|
||||||
|
// TODO remove sleep if not necessary
|
||||||
|
// Sleep in case move_group not loaded
|
||||||
|
rclcpp::sleep_for(2s);
|
||||||
|
|
||||||
|
//rclcpp::executors::SingleThreadedExecutor executor;
|
||||||
|
rclcpp::executors::MultiThreadedExecutor executor;
|
||||||
|
//executor.add_node(lite6);
|
||||||
|
executor.add_node(trajectory_executor);
|
||||||
|
executor.spin();
|
||||||
|
|
||||||
|
rclcpp::shutdown();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@ class DummyController : public RobotController
|
|||||||
virtual void executePath(const std::shared_ptr<rclcpp_action::ServerGoalHandle<ExecuteMotion>> goal_handle)
|
virtual void executePath(const std::shared_ptr<rclcpp_action::ServerGoalHandle<ExecuteMotion>> goal_handle)
|
||||||
{
|
{
|
||||||
RCLCPP_INFO(this->get_logger(), "Executing goal");
|
RCLCPP_INFO(this->get_logger(), "Executing goal");
|
||||||
rclcpp::Rate loop_rate(20);
|
rclcpp::Rate loop_rate(100);
|
||||||
const auto goal = goal_handle->get_goal();
|
const auto goal = goal_handle->get_goal();
|
||||||
auto feedback = std::make_shared<robot_interfaces::action::ExecuteMotion::Feedback>();
|
auto feedback = std::make_shared<robot_interfaces::action::ExecuteMotion::Feedback>();
|
||||||
auto result = std::make_shared<robot_interfaces::action::ExecuteMotion::Result>();
|
auto result = std::make_shared<robot_interfaces::action::ExecuteMotion::Result>();
|
||||||
|
|||||||
@@ -40,6 +40,6 @@ endif()
|
|||||||
|
|
||||||
# Install directories
|
# Install directories
|
||||||
#install(DIRECTORY launch rviz urdf worlds DESTINATION share/${PROJECT_NAME})
|
#install(DIRECTORY launch rviz urdf worlds DESTINATION share/${PROJECT_NAME})
|
||||||
install(DIRECTORY launch DESTINATION share/${PROJECT_NAME})
|
#install(DIRECTORY launch DESTINATION share/${PROJECT_NAME})
|
||||||
|
|
||||||
ament_package()
|
ament_package()
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class DrawingApp(tk.Tk):
|
|||||||
def draw(self,x,y,z):
|
def draw(self,x,y,z):
|
||||||
# putpixel is too slow
|
# putpixel is too slow
|
||||||
#self.img.putpixel((int(x), int(y)), (255, 0, 0))
|
#self.img.putpixel((int(x), int(y)), (255, 0, 0))
|
||||||
r = 4 # radius
|
r = 3 # radius
|
||||||
for xp in range(max(0, x-r), min(self.width-1, x+r)):
|
for xp in range(max(0, x-r), min(self.width-1, x+r)):
|
||||||
for yp in range(max(0, y-r), min(self.height-1, y+r)):
|
for yp in range(max(0, y-r), min(self.height-1, y+r)):
|
||||||
self.arr[xp,yp,0] = 0 #red
|
self.arr[xp,yp,0] = 0 #red
|
||||||
@@ -105,7 +105,7 @@ class DrawingApp(tk.Tk):
|
|||||||
#y = translate(p.y, -0.51, -0.3, 0, self.height)
|
#y = translate(p.y, -0.51, -0.3, 0, self.height)
|
||||||
|
|
||||||
x = int(translate(p.y, -0.5, 0.5, 0, self.width))
|
x = int(translate(p.y, -0.5, 0.5, 0, self.width))
|
||||||
y = int(translate(p.x, -0.3485, 0.1, 0, self.height))
|
y = int(translate(p.x, -0.2485, 0.1, 0, self.height))
|
||||||
|
|
||||||
#x = bound(self.width - x, 0, self.width)
|
#x = bound(self.width - x, 0, self.width)
|
||||||
#y = bound(self.height - y, 0, self.height)
|
#y = bound(self.height - y, 0, self.height)
|
||||||
|
|||||||
Reference in New Issue
Block a user