diff --git a/src/arm_harverster/CMakeLists.txt b/src/arm_harverster/CMakeLists.txt
index ac153c3..6330ee8 100644
--- a/src/arm_harverster/CMakeLists.txt
+++ b/src/arm_harverster/CMakeLists.txt
@@ -7,6 +7,7 @@ find_package(ament_cmake REQUIRED)
install(PROGRAMS
scripts/move_to_point.py
scripts/arm_point_controller.py
+ scripts/mission.py
DESTINATION lib/${PROJECT_NAME}
)
diff --git a/src/arm_harverster/scripts/arm_point_controller.py b/src/arm_harverster/scripts/arm_point_controller.py
index 52492b1..c40f751 100755
--- a/src/arm_harverster/scripts/arm_point_controller.py
+++ b/src/arm_harverster/scripts/arm_point_controller.py
@@ -70,7 +70,7 @@ class CameraArmController(Node):
rclpy.spin_once(self, timeout_sec=0.1)
req = GetPositionFK.Request()
- req.header.frame_id = "world"
+ req.header.frame_id = "base_link"
req.fk_link_names = ["tool_link"] # Name of the tip frame to track
# Pack current joint configuration into the request
@@ -100,14 +100,14 @@ class CameraArmController(Node):
goal_msg.request.pipeline_id = "ompl"
target_pose = PoseStamped()
- target_pose.header.frame_id = "world"
+ target_pose.header.frame_id = "base_link"
target_pose.pose.position.x = float(x)
target_pose.pose.position.y = float(y)
target_pose.pose.position.z = float(z)
target_pose.pose.orientation = self.get_horizontal_camera_quaternion()
position_constraint = PositionConstraint()
- position_constraint.header.frame_id = "world"
+ position_constraint.header.frame_id = "base_link"
position_constraint.link_name = "tool_link"
box = SolidPrimitive()
@@ -126,7 +126,7 @@ class CameraArmController(Node):
position_constraint.weight = 1.0
orient_constraint = OrientationConstraint()
- orient_constraint.header.frame_id = "world"
+ orient_constraint.header.frame_id = "base_link"
orient_constraint.link_name = "tool_link"
orient_constraint.orientation = target_pose.pose.orientation
@@ -145,7 +145,7 @@ class CameraArmController(Node):
goal_handle = send_goal_future.result()
if not goal_handle.accepted:
- self.get_logger().error("❌ Point-to-Point goal rejected by MoveIt!")
+ self.get_logger().error("Point-to-Point goal rejected by MoveIt!")
return False
self.get_logger().info("Goal accepted! Executing path...")
@@ -168,12 +168,12 @@ class CameraArmController(Node):
current_y = current_pose.position.y
current_z = current_pose.position.z
- self.get_logger().info(f"📍 Detected current position: X={current_x:.3f}, Y={current_y:.3f}, Z={current_z:.3f}")
+ self.get_logger().info(f"Detected current position: X={current_x:.3f}, Y={current_y:.3f}, Z={current_z:.3f}")
self.get_logger().info(f"Calculating straight crawl: advancing +{distance}m forward along X...")
req = GetCartesianPath.Request()
req.group_name = "arm"
- req.header.frame_id = "world"
+ req.header.frame_id = "base_link"
req.start_state.is_diff = True
# Target waypoint calculated using live variables
@@ -193,7 +193,7 @@ class CameraArmController(Node):
res = future.result()
if res.fraction < 1.0:
- self.get_logger().warn(f"⚠️ Only calculated {res.fraction*100:.1f}% of path due to link extension limits.")
+ self.get_logger().warn(f" Only calculated {res.fraction*100:.1f}% of path due to link extension limits.")
if res.fraction < 0.5:
return False
@@ -208,10 +208,10 @@ class CameraArmController(Node):
if goal_handle and goal_handle.accepted:
get_result_future = goal_handle.get_result_async()
rclpy.spin_until_future_complete(self, get_result_future)
- self.get_logger().info("✅ Straight camera sweep complete!")
+ self.get_logger().info(" Straight camera sweep complete!")
return True
else:
- self.get_logger().error("❌ Trajectory execution rejected.")
+ self.get_logger().error("Trajectory execution rejected.")
return False
def main(args=None):
@@ -219,14 +219,14 @@ def main(args=None):
node = CameraArmController()
# 1. Send to starting exploration zone
- success = node.send_pt_to_pt_goal(0.6, 0.0, 0.5)
+ success = node.send_pt_to_pt_goal(-0.4, -0.3, 0.5)
if success:
time.sleep(2.0)
# 2. Call the sweep without passing any XYZ parameters!
# It handles the math completely internally.
- node.execute_straight_camera_sweep(distance=0.2)
+ #node.execute_straight_camera_sweep(distance=0.2)
node.destroy_node()
rclpy.shutdown()
diff --git a/src/world_description/mission.py b/src/arm_harverster/scripts/mission.py
old mode 100644
new mode 100755
similarity index 81%
rename from src/world_description/mission.py
rename to src/arm_harverster/scripts/mission.py
index e9e68b9..e274172
--- a/src/world_description/mission.py
+++ b/src/arm_harverster/scripts/mission.py
@@ -20,7 +20,6 @@ class HarvesterStateMachine(Node):
def __init__(self):
super().__init__('harvester_sm_node')
- # --- KONFIGURACJA TEMATÓW ---
odom_topic_name = '/odom'
cmd_vel_topic_name = '/cmd_vel'
@@ -30,15 +29,11 @@ class HarvesterStateMachine(Node):
depth=10
)
- # --- PUBLISHERS & SUBSCRIBERS ---
self.cmd_vel_pub = self.create_publisher(Twist, cmd_vel_topic_name, 10)
self.odom_sub = self.create_subscription(Odometry, odom_topic_name, self.odom_callback, qos_profile)
-
- # Subskrypcja dwóch krzyżujących się LiDARów zgodnie z Twoim planem
self.lidar_left_sub = self.create_subscription(LaserScan, '/lidar_left', self.lidar_left_callback, qos_profile)
self.lidar_right_sub = self.create_subscription(LaserScan, '/lidar_right', self.lidar_right_callback, qos_profile)
- # --- MASZYNA STANÓW ---
self.STATE_INITIALIZING = "INITIALIZING"
self.STATE_GPS_DRIVE = "GPS_DRIVE"
self.STATE_LIDAR_DRIVE = "LIDAR_DRIVE"
@@ -46,36 +41,32 @@ class HarvesterStateMachine(Node):
self.STATE_MISSION_DONE = "MISSION_DONE"
self.current_state = self.STATE_INITIALIZING
- # --- ZMIENNE ODOMETRII ---
self.robot_x, self.robot_y, self.robot_yaw = 0.0, 0.0, 0.0
self.has_odom = False
self.start_offset_x, self.start_offset_y = 0.0, 0.0
- # --- CHMURY PUNKTÓW PO FUZJI (W UKŁADZIE ROBOTA) ---
- self.pts_L = ([], []) # Ściana lewa (zlewana z obu laserów)
- self.pts_R = ([], []) # Ściana prawa (zlewana z obu laserów)
+ self.pts_L = ([], [])
+ self.pts_R = ([], [])
self.avg_left = 0.0
self.avg_right = 0.0
self.end_of_row_detected = False
- # Bufory na surowe wiadomości ROS2
self.latest_left_scan = None
self.latest_right_scan = None
- # --- LOGIKA PRZEJAZDU ---
self.lidar_start_x, self.lidar_start_y = 0.0, 0.0
self.lidar_enter_time = 0.0
self.harvesting_done_in_this_row = False
self.harvest_trigger_distance = 6.0
- # --- PUNKTY DOCELOWE ---
- self.global_waypoints = [{"x": -3.0, "y": 0.8}, {"x": -3.0, "y": 2.4}]
+ # PUNKTY DOCELOWE
+ self.global_waypoints = [{"x": -3.0, "y": 0.8}, {"x": -5.0, "y": -5}]
self.local_waypoints = []
self.current_wp_idx = 0
self.position_reached = False
- # --- PARAMETRY REGULACJI ---
+ # PARAMETRY REGULACJI
self.target_pos_tolerance = 0.4
self.target_heading_tolerance = 0.05
self.lidar_speed = 0.25
@@ -84,11 +75,11 @@ class HarvesterStateMachine(Node):
self.control_timer = self.create_timer(0.1, self.control_loop)
- # --- PYGAME WIZUALIZACJA ---
+ # WIZUALIZACJA
pygame.init()
self.win_size = 600
self.screen = pygame.display.set_mode((self.win_size, self.win_size))
- pygame.display.set_caption("Kombajn: Lokalna Fuzja Układu Współrzędnych (Cross-Eye)")
+ pygame.display.set_caption("HARVESTER")
def odom_callback(self, msg: Odometry):
self.robot_x = msg.pose.pose.position.x
@@ -101,7 +92,7 @@ class HarvesterStateMachine(Node):
if not self.has_odom:
self.start_offset_x, self.start_offset_y = self.robot_x, self.robot_y
- gazebo_spawn_x, gazebo_spawn_y = -10.0, -10.0
+ gazebo_spawn_x, gazebo_spawn_y = -10.0, -2.0
for wp in self.global_waypoints:
self.local_waypoints.append({
@@ -123,26 +114,21 @@ class HarvesterStateMachine(Node):
x_left_wall, y_left_wall = [], []
x_right_wall, y_right_wall = [], []
- # --- SENSOR 1: LEWY LIDAR (Nowe pozycje!) ---
l_msg = self.latest_left_scan
- l_x, l_y, l_yaw = -1.0, 0.5, -0.785398 # <--- TUTAJ ZMIANA
-
- # ... (reszta pętli dla lewego lasera bez zmian) ...
+ l_x, l_y, l_yaw = -1.0, 0.5, -0.785398
+
for i, distance in enumerate(l_msg.ranges):
if math.isinf(distance) or math.isnan(distance) or distance < 3.0 or distance > l_msg.range_max:
continue
angle = l_msg.angle_min + i * l_msg.angle_increment
- # Pozycja punktu względem samego sensora
xs = distance * math.cos(angle)
ys = distance * math.sin(angle)
- # Rzutowanie (Transformacja macierzowa) na układ robota (środek ramy)
xr = l_x + (xs * math.cos(l_yaw) - ys * math.sin(l_yaw))
yr = l_y + (xs * math.sin(l_yaw) + ys * math.cos(l_yaw))
- # Segregacja: jeśli punkt wylądował po lewej stronie robota (Yr > 0), to lewa ściana, inaczej prawa
if yr > 0.0:
x_left_wall.append(xr)
y_left_wall.append(yr)
@@ -153,8 +139,6 @@ class HarvesterStateMachine(Node):
r_msg = self.latest_right_scan
r_x, r_y, r_yaw = -1.0, -0.5, 0.785398 # <--- TUTAJ ZMIANA
- # ... (reszta pętli dla prawego lasera bez zmian) ...
-
for i, distance in enumerate(r_msg.ranges):
if math.isinf(distance) or math.isnan(distance) or distance < 3.0 or distance > r_msg.range_max:
continue
@@ -163,7 +147,6 @@ class HarvesterStateMachine(Node):
xs = distance * math.cos(angle)
ys = distance * math.sin(angle)
- # Rzutowanie na układ robota
xr = r_x + (xs * math.cos(r_yaw) - ys * math.sin(r_yaw))
yr = r_y + (xs * math.sin(r_yaw) + ys * math.cos(r_yaw))
@@ -177,14 +160,12 @@ class HarvesterStateMachine(Node):
self.pts_L = (x_left_wall, y_left_wall)
self.pts_R = (x_right_wall, y_right_wall)
- # Wyliczanie średnich odległości bocznych korytarza dla regulatora PID
min_points = 4
if len(y_left_wall) < min_points and len(y_right_wall) < min_points:
self.end_of_row_detected = True
self.avg_left, self.avg_right = 1.4, 1.4
else:
self.end_of_row_detected = False
- # Średnia odległość punktów od osi podłużnej robota (Y=0)
self.avg_left = sum(y_left_wall) / len(y_left_wall) if y_left_wall else 1.4
self.avg_right = abs(sum(y_right_wall) / len(y_right_wall)) if y_right_wall else 1.4
@@ -194,14 +175,12 @@ class HarvesterStateMachine(Node):
pygame.quit()
sys.exit()
- # Dynamiczny start w oparciu o zebrany komplet tematów z mostka
if self.current_state == self.STATE_INITIALIZING:
if self.has_odom and self.latest_left_scan is not None and self.latest_right_scan is not None:
self.current_state = self.STATE_GPS_DRIVE
self.draw_pygame_window()
return
- # Wykonaj fuzję współrzędnych lokalnych przed podjęciem decyzji o ruchu
self.process_lidar_fusion()
if self.current_state == self.STATE_GPS_DRIVE: self.execute_gps_drive()
@@ -233,7 +212,7 @@ class HarvesterStateMachine(Node):
if abs(yaw_error) > 0.15:
cmd.angular.z = max(min(0.6 * yaw_error, 0.5), -0.5)
else:
- cmd.linear.x = 0.4
+ cmd.linear.x = 2.5
cmd.angular.z = 0.8 * yaw_error
self.cmd_vel_pub.publish(cmd)
else:
@@ -258,7 +237,7 @@ class HarvesterStateMachine(Node):
if self.end_of_row_detected and time_in_lidar > 6.0:
self.stop_robot()
- self.get_logger().info("Wyjazd z korytarza. Powrót do nawigacji GPS.")
+ self.get_logger().info("RETURNING TO GPS.")
self.current_wp_idx += 1
self.current_state = self.STATE_GPS_DRIVE
return
@@ -269,7 +248,6 @@ class HarvesterStateMachine(Node):
self.current_state = self.STATE_HARVESTING
return
- # Logika centrowania oparta o zunifikowane odległości boczne Y po fuzji
diff = self.avg_left - self.avg_right
cmd.linear.x = self.lidar_speed
@@ -293,31 +271,29 @@ class HarvesterStateMachine(Node):
self.cmd_vel_pub.publish(cmd)
def draw_pygame_window(self):
- """Wizualizacja zrzutowanych punktów w lokalnej macierzy robota"""
self.screen.fill((12, 16, 24))
- # Środek okna reprezentuje geometryczny środek kombajnu
cx, cy = self.win_size // 2, self.win_size // 2 + 50
scale = 55.0
- # Siatka radarowa (okręgi co 1 metr)
+ # Siatka radarowa
for r in range(1, 8):
pygame.draw.circle(self.screen, (25, 35, 45), (cx, cy), int(r * scale), 1)
- # Rysowanie obrysu kombajnu (SDF: długość 4.0, szerokość 3.2)
+ # Rysowanie obrysu kombajnu
robot_w = int(3.2 * scale)
robot_h = int(4.0 * scale)
rx = cx - robot_w // 2
ry = cy - robot_h // 2
pygame.draw.rect(self.screen, (55, 65, 80), pygame.Rect(rx, ry, robot_w, robot_h), 2)
- # Pozycja montażowa fizyczna dwóch wewnętrznych LiDARów (X=-2.0, Y= +/- 1.5)
+ # Pozycja montażowa lidarow
pygame.draw.circle(self.screen, (0, 255, 0), (cx - int(1.5*scale), cy + int(2.0*scale)), 5) # Lewy
pygame.draw.circle(self.screen, (255, 150, 0), (cx - int(-1.5*scale), cy + int(2.0*scale)), 5) # Prawy
font = pygame.font.SysFont('Monospace', 13, bold=True)
if self.current_state == self.STATE_INITIALIZING:
- status_text = "INITIALIZING: Oczekiwanie na"
+ status_text = "INITIALIZING..."
if not self.has_odom: status_text += " [ODOM]"
if self.latest_left_scan is None: status_text += " [LIDAR_L]"
if self.latest_right_scan is None: status_text += " [LIDAR_R]"
@@ -325,7 +301,7 @@ class HarvesterStateMachine(Node):
pygame.display.flip()
return
- # Rysowanie przeliczonych chmur punktów (Lewa ściana = zielona, Prawa = pomarańczowa)
+ # Rysowanie przeliczonych chmur punktów
for x, y in zip(self.pts_L[0], self.pts_L[1]):
px = cx - int(y * scale)
py = cy - int(x * scale)
@@ -340,8 +316,8 @@ class HarvesterStateMachine(Node):
# Wyświetlanie tekstów diagnostycznych
self.screen.blit(font.render(f"STAN: {self.current_state}", True, (255, 255, 255)), (15, 15))
- self.screen.blit(font.render(f"DYSTANS OD LEWEJ ŚCIANY: {self.avg_left:.2f}m", True, (100, 255, 100)), (15, 35))
- self.screen.blit(font.render(f"DYSTANS OD PRAWEJ ŚCIANY: {self.avg_right:.2f}m", True, (255, 165, 0)), (15, 55))
+ self.screen.blit(font.render(f"DL: {self.avg_left:.2f}m", True, (100, 255, 100)), (15, 35))
+ self.screen.blit(font.render(f"DR: {self.avg_right:.2f}m", True, (255, 165, 0)), (15, 55))
pygame.display.flip()
def main(args=None):
diff --git a/src/arm_moveit_config/config/six_axis_arm.srdf b/src/arm_moveit_config/config/six_axis_arm.srdf
index 367b070..6e75089 100644
--- a/src/arm_moveit_config/config/six_axis_arm.srdf
+++ b/src/arm_moveit_config/config/six_axis_arm.srdf
@@ -32,4 +32,5 @@
+
diff --git a/src/arm_moveit_config/launch/sim.launch.py b/src/arm_moveit_config/launch/sim.launch.py
index 02d6643..9c90d2e 100644
--- a/src/arm_moveit_config/launch/sim.launch.py
+++ b/src/arm_moveit_config/launch/sim.launch.py
@@ -63,8 +63,15 @@ def generate_launch_description():
arguments=[
'/clock@rosgraph_msgs/msg/Clock[gz.msgs.Clock',
'/world/corn_field_wide/model/harvester_robot/joint_state@sensor_msgs/msg/JointState[gz.msgs.Model',
- '/model/harvester_robot/joint/joint_1/cmd_pos@std_msgs/msg/Float64]gz.msgs.Double'
+ # '/model/harvester_robot/joint/joint_1/cmd_pos@std_msgs/msg/Float64]gz.msgs.Double',
+ # 'cmd_vel@geometry_msgs/msg/Twist]gz.msgs.Twist',
+ # 'model/harvester_robot/odometry@nav_msgs/msg/Odometry[gz.msgs.Odometry',
+ # 'lidar_left@sensor_msgs/msg/LaserScan[gz.msgs.LaserScan',
+ # 'lidar_right@sensor_msgs/msg/LaserScan[gz.msgs.LaserScan',
],
+ remappings=[
+ ('/model/harvester_robot/odometry', '/odom')
+ ],
output='screen'
)
diff --git a/src/world_description/corn_field.sdf b/src/world_description/corn_field.sdf
index dc3481f..8ee484d 100644
--- a/src/world_description/corn_field.sdf
+++ b/src/world_description/corn_field.sdf
@@ -58,6 +58,48 @@
+ C_0_0/home/marcin/arm_ws/src/world_description/models0.02 -0.02 0 0 0 0.44
+ C_0_1/home/marcin/arm_ws/src/world_description/models0.65 0.03 0 0 0 1.57
+ C_0_2/home/marcin/arm_ws/src/world_description/models1.31 -0.01 0 0 0 3.12
+ C_0_3/home/marcin/arm_ws/src/world_description/models1.98 0.04 0 0 0 4.89
+ C_0_4/home/marcin/arm_ws/src/world_description/models2.62 -0.03 0 0 0 0.12
+ C_0_5/home/marcin/arm_ws/src/world_description/models3.25 0.01 0 0 0 2.33
+ C_0_6/home/marcin/arm_ws/src/world_description/models3.91 -0.02 0 0 0 5.67
+ C_0_7/home/marcin/arm_ws/src/world_description/models4.55 0.04 0 0 0 1.11
+ C_0_8/home/marcin/arm_ws/src/world_description/models5.21 -0.01 0 0 0 3.88
+ C_0_9/home/marcin/arm_ws/src/world_description/models5.85 0.02 0 0 0 2.44
+ C_0_10/home/marcin/arm_ws/src/world_description/models6.52 -0.03 0 0 0 1.05
+ C_0_11/home/marcin/arm_ws/src/world_description/models7.17 0.01 0 0 0 4.22
+ C_0_12/home/marcin/arm_ws/src/world_description/models7.83 -0.04 0 0 0 2.11
+ C_0_13/home/marcin/arm_ws/src/world_description/models8.48 0.02 0 0 0 5.89
+ C_0_14/home/marcin/arm_ws/src/world_description/models9.12 -0.01 0 0 0 0.34
+ C_0_15/home/marcin/arm_ws/src/world_description/models9.77 0.04 0 0 0 3.16
+ C_0_16/home/marcin/arm_ws/src/world_description/models10.41 -0.02 0 0 0 1.98
+ C_0_17/home/marcin/arm_ws/src/world_description/models11.06 0.03 0 0 0 4.75
+ C_0_18/home/marcin/arm_ws/src/world_description/models11.72 -0.05 0 0 0 0.88
+ C_0_19/home/marcin/arm_ws/src/world_description/models12.35 0.01 0 0 0 3.61
+
+ C_1_0/home/marcin/arm_ws/src/world_description/models-0.05 1.58 0 0 0 6.12
+ C_1_1/home/marcin/arm_ws/src/world_description/models0.62 1.64 0 0 0 0.88
+ C_1_2/home/marcin/arm_ws/src/world_description/models1.28 1.59 0 0 0 2.55
+ C_1_3/home/marcin/arm_ws/src/world_description/models1.92 1.62 0 0 0 4.12
+ C_1_4/home/marcin/arm_ws/src/world_description/models2.58 1.57 0 0 0 0.33
+ C_1_5/home/marcin/arm_ws/src/world_description/models3.21 1.65 0 0 0 1.99
+ C_1_6/home/marcin/arm_ws/src/world_description/models3.88 1.60 0 0 0 3.44
+ C_1_7/home/marcin/arm_ws/src/world_description/models4.52 1.63 0 0 0 5.21
+ C_1_8/home/marcin/arm_ws/src/world_description/models5.18 1.58 0 0 0 0.77
+ C_1_9/home/marcin/arm_ws/src/world_description/models5.81 1.61 0 0 0 2.15
+ C_1_10/home/marcin/arm_ws/src/world_description/models6.47 1.59 0 0 0 4.91
+ C_1_11/home/marcin/arm_ws/src/world_description/models7.12 1.63 0 0 0 1.34
+ C_1_12/home/marcin/arm_ws/src/world_description/models7.78 1.56 0 0 0 3.82
+ C_1_13/home/marcin/arm_ws/src/world_description/models8.43 1.62 0 0 0 5.02
+ C_1_14/home/marcin/arm_ws/src/world_description/models9.09 1.60 0 0 0 2.27
+ C_1_15/home/marcin/arm_ws/src/world_description/models9.73 1.64 0 0 0 0.41
+ C_1_16/home/marcin/arm_ws/src/world_description/models10.38 1.57 0 0 0 3.19
+ C_1_17/home/marcin/arm_ws/src/world_description/models11.03 1.61 0 0 0 1.15
+ C_1_18/home/marcin/arm_ws/src/world_description/models11.69 1.59 0 0 0 4.63
+ C_1_19/home/marcin/arm_ws/src/world_description/models12.33 1.62 0 0 0 2.85
+
0 0 10 0 0 0
true
@@ -68,7 +110,7 @@
file:///home/marcin/arm_ws/src/world_description/harvester.sdf
- -10 -10 3.3 0 0 0
+ -10 -2 3.3 0 0 0
diff --git a/src/world_description/harvester.sdf b/src/world_description/harvester.sdf
index 34dfd48..5e148d1 100644
--- a/src/world_description/harvester.sdf
+++ b/src/world_description/harvester.sdf
@@ -6,7 +6,7 @@
ogre2
-
+
150.0
@@ -34,10 +34,10 @@
-1.8 1.4 -1.6 0 0 0 0.2 0.2 3.00.2 0.2 0.2 1
-1.8 -1.4 -1.6 0 0 0 0.2 0.2 3.00.2 0.2 0.2 1
- base_linkaxle_fl
- base_linkaxle_fr
- base_linkaxle_bl
- base_linkaxle_br
+ h_base_linkaxle_fl
+ h_base_linkaxle_fr
+ h_base_linkaxle_bl
+ h_base_linkaxle_br
1.8 1.4 -2.9 1.5707 0 0 10.00.1000.100.1
@@ -122,10 +122,10 @@
1 10 gps
- base_linklidar_left_link
- base_linklidar_right_link
- base_linkgps_link
- base_linkcamera_link
+ h_base_linklidar_left_link
+ h_base_linklidar_right_link
+ h_base_linkgps_link
+ h_base_linkcamera_link
axle_flwheel_fl0 1 010000
axle_frwheel_fr0 1 010000
@@ -139,8 +139,8 @@
-
- base_link
+
+ h_base_link
arm::base_link
diff --git a/src/world_description/models/corn.sdf b/src/world_description/models/corn.sdf
index d586de2..751c155 100644
--- a/src/world_description/models/corn.sdf
+++ b/src/world_description/models/corn.sdf
@@ -1,24 +1,267 @@
-
- true
-
-
-
-
- meshes/scene.gltf
-
-
-
-
-
- 0 0 0.5 0 0 0
-
- 0.15 1.0
-
-
-
+
-
-
\ No newline at end of file
+ true
+
+
+
+
+
+
+
+
+
+
+ meshes/corn_stem.glb
+
+
+
+
+
+ 0 0 1.0 0 0 0
+
+
+ 0.025
+ 1.95
+
+
+
+
+
+ 1.0
+
+ 0.35
+ 0.001
+ 0.35
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+
+ 0.00 0.0 0.00 0.0 0 0
+
+
+
+
+ meshes/corn_cob1.glb
+
+
+
+
+
+ 0 0.2 1.05 -0.80 0.0 0.0
+
+
+ 0.03
+ 0.4
+
+
+
+
+
+ 0.25
+
+ 0.001
+ 0.001
+ 0.001
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+
+ 0.00 0.0 0.00 0.0 0 0
+
+
+
+
+ meshes/corn_cob2.glb
+
+
+
+
+
+ -0.13 -0.18 1.28 0.61 -0.75 -0.41
+
+
+ 0.03
+ 0.4
+ -1.535890
+
+
+
+
+ 0.25
+
+ 0.001
+ 0.001
+ 0.001
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+
+ 0.00 0.0 0.00 0.0 0 0
+
+
+
+
+ meshes/corn_cob3.glb
+
+
+
+
+
+ 00.18 -0.04 1.65 0.31 -2.37 -0.16
+
+
+ 0.03
+ 0.4
+
+
+
+
+
+ 0.25
+
+ 0.001
+ 0.001
+ 0.001
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+
+ 0.00 0.0 0.00 0.0 0 0
+
+
+
+
+ meshes/corn_cob4.glb
+
+
+
+
+
+ 0 0 2.17 0 0 0.0
+
+
+ 0.03
+ 0.4
+
+
+
+
+
+ 0.25
+
+ 0.001
+ 0.001
+ 0.001
+ 0
+ 0
+ 0
+
+
+
+ 0 0 1.0 0 0 0
+
+
+
+
+
+
+
+ 0.00 0.0 0.00 0.0 0 0
+
+
+
+
+ meshes/corn_leaf.glb
+
+
+
+
+
+ 0.01
+
+ 0.00001
+ 0.00001
+ 0.00001
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+ corn_stem
+ corn_cob1
+
+
+
+ corn_stem
+ corn_cob2
+
+
+
+ corn_stem
+ corn_cob3
+
+
+
+ corn_stem
+ corn_cob4
+
+
+
+ corn_stem
+ corn_leaf
+
+
+
+
+
diff --git a/src/world_description/models/meshes/corn_cob1.glb b/src/world_description/models/meshes/corn_cob1.glb
new file mode 100644
index 0000000..fa85ea1
Binary files /dev/null and b/src/world_description/models/meshes/corn_cob1.glb differ
diff --git a/src/world_description/models/meshes/corn_cob2.glb b/src/world_description/models/meshes/corn_cob2.glb
new file mode 100644
index 0000000..0015e3f
Binary files /dev/null and b/src/world_description/models/meshes/corn_cob2.glb differ
diff --git a/src/world_description/models/meshes/corn_cob3.glb b/src/world_description/models/meshes/corn_cob3.glb
new file mode 100644
index 0000000..62db2e3
Binary files /dev/null and b/src/world_description/models/meshes/corn_cob3.glb differ
diff --git a/src/world_description/models/meshes/corn_cob4.glb b/src/world_description/models/meshes/corn_cob4.glb
new file mode 100644
index 0000000..5a39750
Binary files /dev/null and b/src/world_description/models/meshes/corn_cob4.glb differ
diff --git a/src/world_description/models/meshes/corn_leaf.glb b/src/world_description/models/meshes/corn_leaf.glb
new file mode 100644
index 0000000..8144b3f
Binary files /dev/null and b/src/world_description/models/meshes/corn_leaf.glb differ
diff --git a/src/world_description/models/meshes/corn_stem.glb b/src/world_description/models/meshes/corn_stem.glb
new file mode 100644
index 0000000..e5eae80
Binary files /dev/null and b/src/world_description/models/meshes/corn_stem.glb differ