feat: add NAV2 perception3D module
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
build/
|
||||
install/
|
||||
log/
|
||||
.colcon/
|
||||
*.log
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
MODULE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
RUNTIME_ROOT="${AUTONOMY_STUDIO_RUNTIME_ROOT:-$HOME/autonomy-studio/runtime/nav2}"
|
||||
exec bash "$RUNTIME_ROOT/docker/docker_build_nav2.sh" "$(dirname "$MODULE_PATH")" "$(basename "$MODULE_PATH")" "${NAV2_DOCKER_IMAGE:-future-nav2-gazebo:humble}" "${ROS_DOMAIN_ID:-0}"
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
MODULE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
RUNTIME_ROOT="${AUTONOMY_STUDIO_RUNTIME_ROOT:-$HOME/autonomy-studio/runtime/nav2}"
|
||||
|
||||
exec bash "$RUNTIME_ROOT/docker/docker_run_nav2.sh" \
|
||||
"lms-nav2-perception3d" \
|
||||
"$(dirname "$MODULE_PATH")" \
|
||||
"$(basename "$MODULE_PATH")" \
|
||||
"${NAV2_DOCKER_IMAGE:-future-nav2:humble}" \
|
||||
"${ROS_DOMAIN_ID:-0}" \
|
||||
sim_mode:=false robot:=mkmini
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
|
||||
|
||||
odometry:
|
||||
ros__parameters:
|
||||
odom_topic: "/vehicle_odom"
|
||||
odom_frame: "odom"
|
||||
base_frame: "base_link"
|
||||
|
||||
pcd_crop:
|
||||
ros__parameters:
|
||||
input_topic: "/raw/lidar"
|
||||
output_topic: "/lidar_filtered"
|
||||
min_z: -5.0
|
||||
max_z: 0.5
|
||||
# min_z: -10.0
|
||||
# max_z: 10.0
|
||||
min_radius: 1.0
|
||||
max_radius: 50.0
|
||||
# min_angle: -1.570796
|
||||
# max_angle: 2.356194
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
odometry:
|
||||
ros__parameters:
|
||||
odom_topic: "/vehicle_odom"
|
||||
odom_frame: "odom"
|
||||
base_frame: "base_link"
|
||||
|
||||
pcd_crop:
|
||||
ros__parameters:
|
||||
input_topic: "/raw/lidar"
|
||||
output_topic: "/lidar_filtered"
|
||||
min_z: -2.5
|
||||
max_z: 1.5
|
||||
min_radius: 2.0
|
||||
max_radius: 30.0
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
|
||||
lidar:
|
||||
x: 0.456
|
||||
y: 0.0
|
||||
z: 1.135
|
||||
roll: 0.0
|
||||
pitch: 0.0
|
||||
yaw: 0.0
|
||||
frame_id: base_link
|
||||
child_frame_id: os_lidar
|
||||
|
||||
imu:
|
||||
x: 0.0
|
||||
y: 0.0
|
||||
z: 0.5
|
||||
roll: 0.0
|
||||
pitch: 0.0
|
||||
yaw: 0.0
|
||||
frame_id: base_link
|
||||
child_frame_id: os_imu
|
||||
|
||||
rgb_front:
|
||||
x: 0.56331
|
||||
y: 0.56343
|
||||
z: 0.80703
|
||||
roll: -0.025
|
||||
pitch: 0.315
|
||||
yaw: 1.035
|
||||
frame_id: base_link
|
||||
child_frame_id: hero/rgb_front
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
|
||||
lidar:
|
||||
x: 0.0
|
||||
y: 0.0
|
||||
z: 0.03618
|
||||
roll: 0.0
|
||||
pitch: 0.0
|
||||
yaw: 2.356194
|
||||
frame_id: base_link
|
||||
child_frame_id: os_lidar
|
||||
|
||||
imu:
|
||||
x: 0.006253
|
||||
y: -0.011775
|
||||
z: 0.007645
|
||||
roll: 0.0
|
||||
pitch: 0.0
|
||||
yaw: 0.0
|
||||
frame_id: base_link
|
||||
child_frame_id: os_imu
|
||||
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
|
||||
lidar:
|
||||
x: 0.456
|
||||
y: 0.0
|
||||
z: 1.135
|
||||
roll: 0.0
|
||||
pitch: 0.0
|
||||
yaw: 0.0
|
||||
frame_id: base_link
|
||||
child_frame_id: os_lidar
|
||||
|
||||
imu:
|
||||
x: 0.0
|
||||
y: 0.0
|
||||
z: 0.5
|
||||
roll: 0.0
|
||||
pitch: 0.0
|
||||
yaw: 0.0
|
||||
frame_id: base_link
|
||||
child_frame_id: os_imu
|
||||
|
||||
rgb_front:
|
||||
x: 0.56331
|
||||
y: 0.56343
|
||||
z: 0.80703
|
||||
roll: -0.025
|
||||
pitch: 0.315
|
||||
yaw: 1.035
|
||||
frame_id: base_link
|
||||
child_frame_id: hero/rgb_front
|
||||
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
|
||||
lidar:
|
||||
x: 0.1
|
||||
y: 0.0
|
||||
z: 0.6
|
||||
roll: 0.0
|
||||
pitch: 0.0
|
||||
yaw: 0.0
|
||||
frame_id: base_link
|
||||
child_frame_id: os_lidar
|
||||
|
||||
imu:
|
||||
x: 0.0
|
||||
y: 0.0
|
||||
z: 0.5
|
||||
roll: 0.0
|
||||
pitch: 0.0
|
||||
yaw: 0.0
|
||||
frame_id: base_link
|
||||
child_frame_id: os_imu
|
||||
|
||||
rgb_front:
|
||||
x: 0.10731
|
||||
y: 0.56343
|
||||
z: -0.27697
|
||||
roll: -0.025
|
||||
pitch: 0.315
|
||||
yaw: 1.035
|
||||
frame_id: base_link
|
||||
child_frame_id: hero/rgb_front
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
|
||||
from ament_index_python.packages import get_package_share_directory
|
||||
|
||||
from launch import LaunchDescription
|
||||
from launch.actions import DeclareLaunchArgument
|
||||
from launch.actions import GroupAction
|
||||
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
|
||||
from launch_ros.actions import Node
|
||||
from launch_ros.descriptions import ParameterFile
|
||||
from nav2_common.launch import RewrittenYaml
|
||||
from launch.actions import OpaqueFunction
|
||||
from launch.substitutions import PythonExpression
|
||||
from launch.conditions import IfCondition
|
||||
|
||||
import os
|
||||
import yaml
|
||||
|
||||
|
||||
ARGUMENTS = [
|
||||
DeclareLaunchArgument('use_sim_time', default_value='true'),
|
||||
DeclareLaunchArgument('sim_mode', default_value='true'),
|
||||
DeclareLaunchArgument('robot', default_value='fr09', choices=['mkmini', 'fr09']),
|
||||
]
|
||||
|
||||
def generate_launch_description():
|
||||
use_sim_time = LaunchConfiguration('use_sim_time')
|
||||
robot = LaunchConfiguration('robot')
|
||||
|
||||
remappings = [('/tf', 'tf'),
|
||||
('/tf_static', 'tf_static')]
|
||||
|
||||
# Directories
|
||||
pkg_perception = get_package_share_directory(
|
||||
'perception3d_pkg')
|
||||
|
||||
params_file = PathJoinSubstitution([
|
||||
pkg_perception,
|
||||
'config',
|
||||
PythonExpression(["'3d_' + '", robot, "' + '.yaml'"])])
|
||||
param_substitutions = {
|
||||
'use_sim_time': use_sim_time,
|
||||
}
|
||||
configured_params = ParameterFile(
|
||||
RewrittenYaml(
|
||||
source_file=params_file,
|
||||
param_rewrites=param_substitutions,
|
||||
convert_types=True),
|
||||
allow_substs=True)
|
||||
|
||||
load_nodes = GroupAction(
|
||||
actions=[
|
||||
Node(
|
||||
package='perception3d_pkg',
|
||||
executable='pcd_crop',
|
||||
name='pcd_crop',
|
||||
output='screen',
|
||||
parameters=[configured_params],
|
||||
remappings=remappings
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
# Create launch description and add actions
|
||||
ld = LaunchDescription(ARGUMENTS)
|
||||
ld.add_action(load_nodes)
|
||||
|
||||
return ld
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>perception3d_pkg</name>
|
||||
<version>0.0.0</version>
|
||||
<description>TODO: Package description</description>
|
||||
<maintainer email="jang1future@gmail.com">dgist</maintainer>
|
||||
<license>TODO: License declaration</license>
|
||||
|
||||
<test_depend>ament_copyright</test_depend>
|
||||
<test_depend>ament_flake8</test_depend>
|
||||
<test_depend>ament_pep257</test_depend>
|
||||
<test_depend>python3-pytest</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_python</build_type>
|
||||
</export>
|
||||
</package>
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
|
||||
#!/usr/bin/env python3
|
||||
import math
|
||||
from typing import Optional
|
||||
|
||||
import rclpy
|
||||
from rclpy.node import Node
|
||||
|
||||
from std_msgs.msg import Float32
|
||||
from sensor_msgs.msg import Imu
|
||||
from rosgraph_msgs.msg import Clock
|
||||
from nav_msgs.msg import Odometry
|
||||
from geometry_msgs.msg import Quaternion, TransformStamped
|
||||
from tf2_ros import TransformBroadcaster
|
||||
|
||||
|
||||
def quat_to_yaw(x: float, y: float, z: float, w: float) -> float:
|
||||
siny_cosp = 2.0 * (w * z + x * y)
|
||||
cosy_cosp = 1.0 - 2.0 * (y * y + z * z)
|
||||
return math.atan2(siny_cosp, cosy_cosp)
|
||||
|
||||
|
||||
def yaw_to_quaternion(yaw: float) -> Quaternion:
|
||||
q = Quaternion()
|
||||
q.x = 0.0
|
||||
q.y = 0.0
|
||||
q.z = math.sin(yaw * 0.5)
|
||||
q.w = math.cos(yaw * 0.5)
|
||||
return q
|
||||
|
||||
|
||||
def normalize_angle(angle: float) -> float:
|
||||
while angle > math.pi:
|
||||
angle -= 2.0 * math.pi
|
||||
while angle < -math.pi:
|
||||
angle += 2.0 * math.pi
|
||||
return angle
|
||||
|
||||
|
||||
def stamp_to_sec(stamp) -> float:
|
||||
return float(stamp.sec) + float(stamp.nanosec) * 1e-9
|
||||
|
||||
|
||||
class SpeedImuOdomNode(Node):
|
||||
def __init__(self):
|
||||
super().__init__('speed_imu_odom_node')
|
||||
|
||||
# Parameters
|
||||
self.declare_parameter('odom_topic', '/vehicle_odom')
|
||||
self.declare_parameter('odom_frame', 'odom')
|
||||
self.declare_parameter('base_frame', 'base_link')
|
||||
|
||||
self.odom_topic = self.get_parameter('odom_topic').value
|
||||
self.odom_frame = self.get_parameter('odom_frame').value
|
||||
self.base_frame = self.get_parameter('base_frame').value
|
||||
|
||||
self.declare_parameter('pose_cov_x', 0.5)
|
||||
self.declare_parameter('pose_cov_y', 0.5)
|
||||
self.declare_parameter('pose_cov_yaw', 0.2)
|
||||
self.declare_parameter('twist_cov_vx', 0.2)
|
||||
self.declare_parameter('twist_cov_vy', 0.2)
|
||||
self.declare_parameter('twist_cov_wz', 0.1)
|
||||
|
||||
self.pose_cov_x = self.get_parameter('pose_cov_x').get_parameter_value().double_value
|
||||
self.pose_cov_y = self.get_parameter('pose_cov_y').get_parameter_value().double_value
|
||||
self.pose_cov_yaw = self.get_parameter('pose_cov_yaw').get_parameter_value().double_value
|
||||
self.twist_cov_vx = self.get_parameter('twist_cov_vx').get_parameter_value().double_value
|
||||
self.twist_cov_vy = self.get_parameter('twist_cov_vy').get_parameter_value().double_value
|
||||
self.twist_cov_wz = self.get_parameter('twist_cov_wz').get_parameter_value().double_value
|
||||
|
||||
self.x = 0.0
|
||||
self.y = 0.0
|
||||
self.yaw = 0.0
|
||||
|
||||
self.max_dt = 0.1
|
||||
|
||||
# State
|
||||
self.speed_mps: float = 0.0
|
||||
self.current_yaw: Optional[float] = None
|
||||
self.last_yaw: Optional[float] = None
|
||||
self.last_pub_time: Optional[float] = None
|
||||
|
||||
self.x = 0.0
|
||||
self.y = 0.0
|
||||
|
||||
self.has_speed = False
|
||||
self.has_imu = False
|
||||
|
||||
self.ground_truth_odom: Optional[Odometry] = None
|
||||
|
||||
# Pub/Sub
|
||||
self.odom_pub = self.create_publisher(Odometry, self.odom_topic, 50)
|
||||
self.tf_broadcaster = TransformBroadcaster(self)
|
||||
|
||||
self.create_subscription(Float32, '/raw/speed', self.speed_cb, 50)
|
||||
self.create_subscription(Imu, '/raw/imu', self.imu_cb, 50)
|
||||
|
||||
self.get_logger().info('SpeedImuOdomNode started')
|
||||
self.get_logger().info(f'odom_topic: {self.odom_topic}')
|
||||
|
||||
def speed_cb(self, msg: Float32):
|
||||
self.speed_mps = float(msg.data)
|
||||
self.has_speed = True
|
||||
|
||||
def imu_cb(self, msg: Imu):
|
||||
self.has_imu = True
|
||||
|
||||
# speed가 아직 없으면 선택적으로 skip
|
||||
if not self.has_speed:
|
||||
return
|
||||
|
||||
# IMU timestamp 우선 사용
|
||||
stamp = msg.header.stamp
|
||||
now_sec = stamp_to_sec(stamp)
|
||||
|
||||
omega = float(msg.angular_velocity.z)
|
||||
|
||||
if self.last_pub_time is None:
|
||||
self.last_pub_time = now_sec
|
||||
self.current_yaw = self.yaw
|
||||
self.last_yaw = self.yaw
|
||||
# 첫 샘플은 dt가 없으므로 현재 yaw로 publish
|
||||
self.publish_odom(stamp, self.yaw, self.speed_mps, omega)
|
||||
return
|
||||
|
||||
dt = now_sec - self.last_pub_time
|
||||
if dt <= 0.0:
|
||||
# 시간 역전/동일시간이면 적분하지 않고 현재 yaw만 publish
|
||||
self.publish_odom(stamp, self.yaw, self.speed_mps, omega)
|
||||
return
|
||||
|
||||
# 긴 공백은 과적분 방지
|
||||
if dt > self.max_dt:
|
||||
dt = self.max_dt
|
||||
|
||||
# angular velocity integration
|
||||
self.yaw += omega * dt
|
||||
self.yaw = normalize_angle(self.yaw)
|
||||
|
||||
# position integration
|
||||
self.x += self.speed_mps * math.cos(self.yaw) * dt
|
||||
self.y += self.speed_mps * math.sin(self.yaw) * dt
|
||||
|
||||
self.current_yaw = self.yaw
|
||||
self.last_yaw = self.yaw
|
||||
self.last_pub_time = now_sec
|
||||
|
||||
self.publish_odom(stamp, self.yaw, self.speed_mps, omega)
|
||||
|
||||
def publish_odom(self, stamp, yaw: float, v: float, omega: float):
|
||||
odom = Odometry()
|
||||
odom.header.stamp = stamp
|
||||
odom.header.frame_id = self.odom_frame
|
||||
odom.child_frame_id = self.base_frame
|
||||
|
||||
odom.pose.pose.position.x = self.x
|
||||
odom.pose.pose.position.y = self.y
|
||||
odom.pose.pose.position.z = 0.0
|
||||
odom.pose.pose.orientation = yaw_to_quaternion(yaw)
|
||||
|
||||
odom.twist.twist.linear.x = v
|
||||
odom.twist.twist.linear.y = 0.0
|
||||
odom.twist.twist.linear.z = 0.0
|
||||
odom.twist.twist.angular.x = 0.0
|
||||
odom.twist.twist.angular.y = 0.0
|
||||
odom.twist.twist.angular.z = omega
|
||||
|
||||
odom.pose.covariance = [
|
||||
self.pose_cov_x, 0.0, 0.0, 0.0, 0.0, 0.0,
|
||||
0.0, self.pose_cov_y, 0.0, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 999.0,0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 999.0,0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0, 999.0,0.0,
|
||||
0.0, 0.0, 0.0, 0.0, 0.0, self.pose_cov_yaw
|
||||
]
|
||||
|
||||
odom.twist.covariance = [
|
||||
self.twist_cov_vx, 0.0, 0.0, 0.0, 0.0, 0.0,
|
||||
0.0, self.twist_cov_vy, 0.0, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 999.0,0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 999.0,0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0, 999.0,0.0,
|
||||
0.0, 0.0, 0.0, 0.0, 0.0, self.twist_cov_wz
|
||||
]
|
||||
|
||||
self.odom_pub.publish(odom)
|
||||
|
||||
tf_msg = TransformStamped()
|
||||
tf_msg.header.stamp = stamp
|
||||
tf_msg.header.frame_id = self.odom_frame
|
||||
tf_msg.child_frame_id = self.base_frame
|
||||
tf_msg.transform.translation.x = self.x
|
||||
tf_msg.transform.translation.y = self.y
|
||||
tf_msg.transform.translation.z = 0.0
|
||||
tf_msg.transform.rotation = yaw_to_quaternion(yaw)
|
||||
self.tf_broadcaster.sendTransform(tf_msg)
|
||||
|
||||
|
||||
def main(args=None):
|
||||
rclpy.init(args=args)
|
||||
node = SpeedImuOdomNode()
|
||||
try:
|
||||
rclpy.spin(node)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
node.destroy_node()
|
||||
rclpy.shutdown()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import rclpy
|
||||
from rclpy.node import Node
|
||||
|
||||
from sensor_msgs.msg import PointCloud2
|
||||
import sensor_msgs_py.point_cloud2 as pc2
|
||||
|
||||
import numpy as np
|
||||
|
||||
class PointCloudCrop(Node):
|
||||
def __init__(self):
|
||||
super().__init__('pcd_crop')
|
||||
|
||||
self.declare_parameter('min_z', -2.5)
|
||||
self.declare_parameter('max_z', -0.5)
|
||||
self.declare_parameter('min_radius', 5.0) # 너무 가까운 점 제거
|
||||
self.declare_parameter('max_radius', 30.0) # 너무 먼 점 제거
|
||||
self.declare_parameter('input_topic', '/raw/lidar')
|
||||
self.declare_parameter('output_topic', '/lidar_filtered')
|
||||
|
||||
self.min_z = self.get_parameter('min_z').value
|
||||
self.max_z = self.get_parameter('max_z').value
|
||||
self.min_radius = self.get_parameter('min_radius').value
|
||||
self.max_radius = self.get_parameter('max_radius').value
|
||||
|
||||
input_topic = self.get_parameter('input_topic').value
|
||||
output_topic = self.get_parameter('output_topic').value
|
||||
|
||||
self.declare_parameter('min_angle', (-np.pi)) # rad
|
||||
self.declare_parameter('max_angle', (np.pi)) # rad
|
||||
|
||||
self.min_angle = self.get_parameter('min_angle').value
|
||||
self.max_angle = self.get_parameter('max_angle').value
|
||||
|
||||
self.sub = self.create_subscription(
|
||||
PointCloud2,
|
||||
input_topic,
|
||||
self.callback,
|
||||
10
|
||||
)
|
||||
|
||||
self.pub = self.create_publisher(
|
||||
PointCloud2,
|
||||
output_topic,
|
||||
10
|
||||
)
|
||||
|
||||
self.get_logger().info(
|
||||
f"Crop started: Z[{self.min_z}, {self.max_z}] "
|
||||
f"Radius[{self.min_radius}, {self.max_radius}]"
|
||||
f"Angle[{self.min_angle}, {self.max_angle}]"
|
||||
)
|
||||
|
||||
def callback(self, msg: PointCloud2):
|
||||
pts = pc2.read_points(
|
||||
msg,
|
||||
field_names=("x", "y", "z"),
|
||||
skip_nans=True
|
||||
)
|
||||
|
||||
if pts.shape[0] == 0:
|
||||
return
|
||||
|
||||
# structured array -> 일반 (N,3) float32 배열
|
||||
points = np.stack(
|
||||
(pts["x"], pts["y"], pts["z"]), axis=-1).astype(np.float32, copy=False)
|
||||
|
||||
x = points[:, 0]
|
||||
y = points[:, 1]
|
||||
z = points[:, 2]
|
||||
|
||||
min_r2 = self.min_radius * self.min_radius
|
||||
max_r2 = self.max_radius * self.max_radius
|
||||
r2 = x * x + y * y
|
||||
|
||||
angles = np.arctan2(-y, -x)
|
||||
|
||||
if self.min_angle < self.max_angle:
|
||||
angle_mask = (angles >= self.min_angle) & (angles <= self.max_angle)
|
||||
else:
|
||||
angle_mask = (angles >= self.min_angle) | (angles <= self.max_angle)
|
||||
|
||||
mask = (
|
||||
(z >= self.min_z) &
|
||||
(z <= self.max_z) &
|
||||
(r2 >= min_r2) &
|
||||
(r2 <= max_r2) &
|
||||
angle_mask
|
||||
)
|
||||
|
||||
filtered = points[mask]
|
||||
|
||||
if filtered.shape[0] == 0:
|
||||
return
|
||||
|
||||
filtered_msg = pc2.create_cloud_xyz32(msg.header, filtered.tolist())
|
||||
self.pub.publish(filtered_msg)
|
||||
|
||||
|
||||
def main(args=None):
|
||||
rclpy.init(args=args)
|
||||
node = PointCloudCrop()
|
||||
rclpy.spin(node)
|
||||
node.destroy_node()
|
||||
rclpy.shutdown()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
def main():
|
||||
print('Hi from perception3d_pkg.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
[develop]
|
||||
script_dir=$base/lib/perception3d_pkg
|
||||
[install]
|
||||
install_scripts=$base/lib/perception3d_pkg
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
|
||||
import os
|
||||
from glob import glob
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
package_name = 'perception3d_pkg'
|
||||
|
||||
setup(
|
||||
name=package_name,
|
||||
version='0.0.0',
|
||||
packages=find_packages(exclude=['test']),
|
||||
data_files=[
|
||||
('share/ament_index/resource_index/packages',
|
||||
['resource/' + package_name]),
|
||||
('share/' + package_name, ['package.xml']),
|
||||
(os.path.join('share', package_name, 'launch'), glob('launch/*.launch.py')),
|
||||
(os.path.join('share', package_name, 'config'), glob('config/*.yaml')),
|
||||
],
|
||||
install_requires=['setuptools'],
|
||||
zip_safe=True,
|
||||
maintainer='dgist',
|
||||
maintainer_email='jang1future@gmail.com',
|
||||
description='TODO: Package description',
|
||||
license='TODO: License declaration',
|
||||
extras_require={
|
||||
'test': [
|
||||
'pytest',
|
||||
],
|
||||
},
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'test = perception3d_pkg.test:main',
|
||||
'pcd_crop = perception3d_pkg.pcd_crop:main'
|
||||
],
|
||||
},
|
||||
)
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
# Copyright 2015 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_copyright.main import main
|
||||
import pytest
|
||||
|
||||
|
||||
# Remove the `skip` decorator once the source file(s) have a copyright header
|
||||
@pytest.mark.skip(reason='No copyright header has been placed in the generated source file.')
|
||||
@pytest.mark.copyright
|
||||
@pytest.mark.linter
|
||||
def test_copyright():
|
||||
rc = main(argv=['.', 'test'])
|
||||
assert rc == 0, 'Found errors'
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
# Copyright 2017 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_flake8.main import main_with_errors
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.flake8
|
||||
@pytest.mark.linter
|
||||
def test_flake8():
|
||||
rc, errors = main_with_errors(argv=[])
|
||||
assert rc == 0, \
|
||||
'Found %d code style errors / warnings:\n' % len(errors) + \
|
||||
'\n'.join(errors)
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
# Copyright 2015 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_pep257.main import main
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.linter
|
||||
@pytest.mark.pep257
|
||||
def test_pep257():
|
||||
rc = main(argv=['.', 'test'])
|
||||
assert rc == 0, 'Found code style errors / warnings'
|
||||
Reference in New Issue
Block a user