ALICE4 코드 예제
ALICE4 로봇을 프로그래밍하는 실제 예제들을 소개합니다.
🏗️ 개발 환경 설정
ROS2 워크스페이스 생성
# 워크스페이스 생성
mkdir -p ~/alice4_ws/src
cd ~/alice4_ws/src
# ALICE4 패키지 클론
git clone https://github.com/aeirobot/alice4_msgs.git
git clone https://github.com/aeirobot/alice4_control.git
# 의존성 설치
cd ~/alice4_ws
rosdep install --from-paths src --ignore-src -r -y
# 빌드
colcon build --symlink-install
source install/setup.bash
Python 환경 설정
# 가상환경 생성 (선택사항)
python3 -m venv alice4_env
source alice4_env/bin/activate
# 필수 패키지 설치
pip install rclpy
pip install numpy
pip install matplotlib
📝 기본 예제
1. 로봇 상태 모니터링
- Python
- C++
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import JointState
from alice4_msgs.msg import RobotStatus
class Alice4Monitor(Node):
def __init__(self):
super().__init__('alice4_monitor')
# 조인트 상태 구독
self.joint_sub = self.create_subscription(
JointState,
'/alice4/joint_states',
self.joint_callback,
10
)
# 로봇 상태 구독
self.status_sub = self.create_subscription(
RobotStatus,
'/alice4/status',
self.status_callback,
10
)
def joint_callback(self, msg):
self.get_logger().info(f'Joint positions: {msg.position}')
def status_callback(self, msg):
status_text = "Ready" if msg.ready else "Not Ready"
self.get_logger().info(f'Robot status: {status_text}')
def main(args=None):
rclpy.init(args=args)
monitor = Alice4Monitor()
rclpy.spin(monitor)
monitor.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
#include <rclcpp/rclcpp.hpp>
#include <sensor_msgs/msg/joint_state.hpp>
#include <alice4_msgs/msg/robot_status.hpp>
class Alice4Monitor : public rclcpp::Node {
public:
Alice4Monitor() : Node("alice4_monitor") {
// 조인트 상태 구독
joint_sub_ = this->create_subscription<sensor_msgs::msg::JointState>(
"/alice4/joint_states", 10,
std::bind(&Alice4Monitor::joint_callback, this, std::placeholders::_1));
// 로봇 상태 구독
status_sub_ = this->create_subscription<alice4_msgs::msg::RobotStatus>(
"/alice4/status", 10,
std::bind(&Alice4Monitor::status_callback, this, std::placeholders::_1));
}
private:
void joint_callback(const sensor_msgs::msg::JointState::SharedPtr msg) {
RCLCPP_INFO(this->get_logger(), "Joint positions received");
}
void status_callback(const alice4_msgs::msg::RobotStatus::SharedPtr msg) {
std::string status = msg->ready ? "Ready" : "Not Ready";
RCLCPP_INFO(this->get_logger(), "Robot status: %s", status.c_str());
}
rclcpp::Subscription<sensor_msgs::msg::JointState>::SharedPtr joint_sub_;
rclcpp::Subscription<alice4_msgs::msg::RobotStatus>::SharedPtr status_sub_;
};
int main(int argc, char * argv[]) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<Alice4Monitor>());
rclcpp::shutdown();
return 0;
}
2. 간단한 움직임 제어
포인트 투 포인트 이동
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint
import math
class Alice4Mover(Node):
def __init__(self):
super().__init__('alice4_mover')
self.trajectory_pub = self.create_publisher(
JointTrajectory,
'/alice4/joint_trajectory_controller/joint_trajectory',
10
)
def move_to_position(self, joint_positions, duration=2.0):
# 트래젝토리 메시지 생성
trajectory = JointTrajectory()
trajectory.joint_names = [
'joint_1', 'joint_2', 'joint_3',
'joint_4', 'joint_5', 'joint_6'
]
# 포인트 생성
point = JointTrajectoryPoint()
point.positions = joint_positions
point.velocities = [0.0] * 6
point.time_from_start.sec = int(duration)
point.time_from_start.nanosec = int((duration % 1) * 1e9)
trajectory.points.append(point)
# 트래젝토리 발행
self.trajectory_pub.publish(trajectory)
self.get_logger().info('Trajectory published')
def main(args=None):
rclpy.init(args=args)
mover = Alice4Mover()
# 홈 포지션으로 이동 (모든 조인트 0도)
home_position = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
mover.move_to_position(home_position, 3.0)
# 2초 대기 후 종료
rclpy.spin_once(mover, timeout_sec=2.0)
mover.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
3. 그리퍼 연동 예제
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from std_msgs.msg import Float64
import time
class PickAndPlaceDemo(Node):
def __init__(self):
super().__init__('pick_and_place_demo')
# 그리퍼 제어 퍼블리셔
self.gripper_pub = self.create_publisher(
Float64,
'/alice4/gripper_controller/command',
10
)
# 조인트 트래젝토리 퍼블리셔 (위 예제 참고)
# self.trajectory_pub = ...
def open_gripper(self):
cmd = Float64()
cmd.data = 0.08 # 열린 상태 (미터)
self.gripper_pub.publish(cmd)
self.get_logger().info('Gripper opened')
def close_gripper(self):
cmd = Float64()
cmd.data = 0.0 # 닫힌 상태
self.gripper_pub.publish(cmd)
self.get_logger().info('Gripper closed')
def pick_sequence(self):
"""픽 앤 플레이스 시퀀스"""
# 1. 그리퍼 열기
self.open_gripper()
time.sleep(1)
# 2. 픽 포지션으로 이동
pick_position = [0.3, 0.2, 0.1, 0.0, 1.57, 0.0]
self.move_to_position(pick_position)
# 3. 그리퍼 닫기 (물체 잡기)
time.sleep(1)
self.close_gripper()
time.sleep(1)
# 4. 플레이스 포지션으로 이동
place_position = [0.1, -0.2, 0.3, 0.0, 1.57, 0.0]
self.move_to_position(place_position)
# 5. 그리퍼 열기 (물체 놓기)
time.sleep(1)
self.open_gripper()
# move_to_position 메서드는 위 예제 참고
🔧 고급 예제
경로 계획 및 실행
import numpy as np
from alice4_motion import MotionPlanner
class PathPlannerDemo:
def __init__(self):
self.planner = MotionPlanner()
self.planner.load_robot_model('alice4.urdf')
def plan_cartesian_path(self, waypoints):
"""직교 좌표계 웨이포인트들 사이의 경로 계획"""
path = []
for i in range(len(waypoints) - 1):
start = waypoints[i]
end = waypoints[i + 1]
# 직선 경로 생성 (간단한 예제)
num_points = 50
for t in np.linspace(0, 1, num_points):
point = start + t * (end - start)
path.append(point)
return path
def execute_path(self, cartesian_path):
"""계획된 경로 실행"""
joint_path = []
for pose in cartesian_path:
# 역기구학으로 조인트 각도 계산
joint_angles = self.planner.inverse_kinematics(pose)
if joint_angles is not None:
joint_path.append(joint_angles)
# 조인트 트래젝토리로 변환하여 실행
# (실제 구현에서는 속도/가속도 프로필 고려)
return joint_path
# 사용 예제
if __name__ == '__main__':
demo = PathPlannerDemo()
# 웨이포인트 정의 (x, y, z, rx, ry, rz)
waypoints = [
[0.3, 0.0, 0.2, 0.0, 3.14, 0.0],
[0.3, 0.2, 0.2, 0.0, 3.14, 0.0],
[0.1, 0.2, 0.3, 0.0, 3.14, 0.0],
]
# 경로 계획 및 실행
cartesian_path = demo.plan_cartesian_path(waypoints)
joint_trajectory = demo.execute_path(cartesian_path)
시뮬레이션 환경 설정
# simulation.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
import os
def generate_launch_description():
pkg_share = os.path.join(
get_package_share_directory('alice4_gazebo'),
'launch'
)
return LaunchDescription([
# Gazebo 시뮬레이션 시작
IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(pkg_share, 'gazebo.launch.py')
)
),
# ALICE4 로봇 스폰
Node(
package='gazebo_ros',
executable='spawn_entity.py',
arguments=[
'-topic', '/robot_description',
'-entity', 'alice4'
],
output='screen'
),
# 조인트 상태 퍼블리셔
Node(
package='joint_state_publisher_gui',
executable='joint_state_publisher_gui',
name='joint_state_publisher_gui',
output='screen'
),
# RViz 시각화
Node(
package='rviz2',
executable='rviz2',
name='rviz2',
arguments=['-d', os.path.join(pkg_share, 'config.rviz')],
output='screen'
)
])
📚 API 레퍼런스
주요 메시지 타입
| 메시지 타입 | 설명 | 토픽 |
|---|---|---|
JointState | 조인트 각도 및 속도 | /alice4/joint_states |
RobotStatus | 로봇 상태 정보 | /alice4/status |
JointTrajectory | 조인트 트래젝토리 명령 | /alice4/joint_trajectory_controller/joint_trajectory |
PoseStamped | 엔드이펙터 포즈 | /alice4/ee_pose |
서비스 인터페이스
# 캘리브레이션 서비스 호출
from alice4_srvs.srv import Calibrate
import rclpy
client = node.create_client(Calibrate, '/alice4/calibrate')
request = Calibrate.Request()
future = client.call_async(request)
rclpy.spin_until_future_complete(node, future)
🔍 디버깅 및 로깅
로깅 설정
import logging
# ROS2 로깅 레벨 설정
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('alice4_app')
# ROS2 노드 로깅
node.get_logger().set_level(rclpy.logging.LoggingSeverity.INFO)
오류 처리
try:
# 로봇 제어 코드
mover.move_to_position(target_position)
except Exception as e:
node.get_logger().error(f'Movement failed: {str(e)}')
# 복구 로직
mover.emergency_stop()
프로 팁
- 복잡한 작업의 경우 MoveIt2 라이브러리를 활용하세요
- 실시간 성능이 필요한 경우 C++로 구현을 고려하세요
- 시뮬레이션 환경에서 먼저 테스트한 후 실제 로봇에 적용하세요
다음 단계
이제 ALICE4를 자유자재로 제어할 수 있습니다. 실제 응용 분야에 맞는 고급 튜토리얼을 확인하세요.