Hi,
I am trying to using RODODK for OpenCV simulation.
However, I am having trouble figuring out why the position is off by a few mm in the x and y.
The reprojection is .15 which should be really good. Is my math wrong?
Hi,
I am trying to using RODODK for OpenCV simulation.
However, I am having trouble figuring out why the position is off by a few mm in the x and y.
The reprojection is .15 which should be really good. Is my math wrong?
import cv2
import numpy as np
import cv2.aruco as aruco
from robodk.robomath import Mat
from robodk.robolink import *
board = cv2.aruco.CharucoBoard(
size=(7,5),
squareLength=0.023444,
markerLength=0.017439,
dictionary=cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_6X6_50)
)
picture_range=16
RDK= Robolink()
Poses = [RDK.Item(f'Target {i}') for i in range(1, picture_range)]
for i in range(1, picture_range):
globals()[f"Pose_{i}"] = RDK.Item(f"Target {i}")
camera= RDK.Item('Cali')
robot = RDK.Item("Doosan Robotics H2515")
robot.setSpeed(1000) # mm/s
robot.setAcceleration(1000) # mm/s²
if not camera.Valid():
print('CAMERA NOT FOUND')
exit()
calibration_file = "C:/Users//PycharmProjects/GolfPutty/CalibrationFiles/calibration.xml"
def chaUco_Calibration(calibration_file):
# Detection setup
# Calibration data collection
all_corners = []
all_ids = []
image_size = None
calibration_complete = False
detector = aruco.CharucoDetector(board)
while True:
for i, pose in enumerate(Poses):
robot.MoveJ(pose)
# Get frame
bytes_img = RDK.Cam2D_Snapshot("", camera)
if not bytes_img:
continue
nparr = np.frombuffer(bytes_img, np.uint8)
frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
cv2.imwrite(f"C:/Users//PycharmProjects/GolfPutty/CalibrationFiles/snap_{i}.png", frame)
if image_size is None:
image_size = frame.shape[1], frame.shape[0]
# Detection
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Detect ChArUco board
charuco_corners, charuco_ids, marker_corners, marker_ids = detector.detectBoard(frame)
if charuco_ids is not None:
frame = cv2.aruco.drawDetectedMarkers(frame, marker_corners, marker_ids)
frame = cv2.aruco.drawDetectedCornersCharuco(frame, charuco_corners, charuco_ids)
#display_text = "Press 'c' to capture calibration frame"
if charuco_ids is not None:
frame = cv2.aruco.drawDetectedMarkers(frame, marker_corners, marker_ids)
frame = cv2.aruco.drawDetectedCornersCharuco(frame, charuco_corners, charuco_ids)
#key = cv2.waitKey(1)
all_corners.append(charuco_corners)
all_ids.append(charuco_ids)
print(f"Captured frame {len(all_corners)}")
# Calibrate when enough frames (press 'f' to force)
key = cv2.waitKey(1)
if ((len(all_corners) >= picture_range)) and not calibration_complete:
print("Calibrating...")
ret, mtx, dist, rvecs, tvecs = cv2.aruco.calibrateCameraCharuco(
all_corners, all_ids, board, image_size, None, None)
if ret < 1: # Good reprojection error
fs = cv2.FileStorage(calibration_file, cv2.FILE_STORAGE_WRITE)
if not fs.isOpened():
print("Error: Unable to open file for writing. Check file path and permissions.")
exit(1) # Stop execution
fs.write("Camera_Matrix", mtx)
fs.write("Distortion_Coefficients", dist)
print("Calibration complete and uploaded to RoboDK!")
print(f"Reprojection error: {ret:.2f} pixels")
return
else:
print(f"Poor calibration (error: {ret:.2f} px). Capture more frames.")
# Display info
#cv2.putText(frame, display_text, (10, 30),
# cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
#cv2.putText(frame, f"Frames captured: {len(all_corners)}/15", (10, 60),
# cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.imshow('ChArUco Calibration', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
if __name__ == "__main__":
chaUco_Calibration(calibration_file) # Only runs when executed directly
import cv2
import cv2.aruco as aruco
import numpy as np
from robodk.robolink import *
from robodk.robomath import * # RoboDK Math functions
# Use your board's dictionary
import numpy as np
import cv2
def resize_1080p_to_720p(frame):
#return (cv2.resize(frame, (1280, 720), interpolation=cv2.INTER_LINEAR))
return frame
def align_z_up(rvec):
# Convert rotation vector to rotation matrix
R, _ = cv2.Rodrigues(rvec)
# Desired Z axis in world/camera coordinates
z_up = np.array([0, 0, 1], dtype=float)
# Keep the current X axis as close as possible to original
x_axis = R[:, 0]
# Recompute Y as cross product to keep orthogonal
y_axis = np.cross(z_up, x_axis)
y_axis /= np.linalg.norm(y_axis)
# Recompute X as orthogonal to both Y and Z
x_axis = np.cross(y_axis, z_up)
x_axis /= np.linalg.norm(x_axis)
# Build the new rotation matrix
R_new = np.column_stack((x_axis, y_axis, z_up))
# Convert back to rotation vector
rvec_new, _ = cv2.Rodrigues(R_new)
return rvec_new, R_new
def scale_camera_matrix_1080p_to_720p(mtx_1080p):
scale_x = 1280 / 1920
scale_y = 720 / 1080
mtx_720p = mtx_1080p.copy()
mtx_720p[0, 0] *= scale_x # fx
mtx_720p[1, 1] *= scale_y # fy
mtx_720p[0, 2] *= scale_x # cx
mtx_720p[1, 2] *= scale_y # cy
return mtx_1080p
board = cv2.aruco.CharucoBoard(
size=(7,5),
squareLength=0.023444,
markerLength=0.017439,
dictionary=cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_6X6_50)
)
calibration_file = "C:/Users//PycharmProjects/GolfPutty/CalibrationFiles/calibration.xml"
marker_length=0.017439
RDK=Robolink()
camera= RDK.Item('Cali')
robot = RDK.Item("Doosan Robotics H2515")
fs = cv2.FileStorage(calibration_file, cv2.FILE_STORAGE_READ)
mtx = fs.getNode("Camera_Matrix").mat()
dist = fs.getNode("Distortion_Coefficients").mat()
fs.release()
Starting_pose= RDK.Item('Start')
Marker_pose= RDK.Item('markers')
robot.MoveJ(Starting_pose)
detector = aruco.CharucoDetector(board)
#zero_dist = np.zeros_like(dist)
#dist=zero_dist
while True:
bytes_img = RDK.Cam2D_Snapshot("", camera)
nparr = np.frombuffer(bytes_img, np.uint8)
frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
charuco_corners, charuco_ids, marker_corners, marker_ids = detector.detectBoard(frame)
if marker_ids is not None:
aruco.drawDetectedMarkers(frame, marker_corners, marker_ids)
# Iterate through all detected markers
for i, marker_id in enumerate(marker_ids.flatten()):
if marker_id == 15: # The marker you care about
# Estimate pose of the marker
rvec, tvec, _ = aruco.estimatePoseSingleMarkers(
marker_corners[i], marker_length, mtx, dist
)
print("marker_length:", marker_length)
# Draw axis on that marker
cv2.drawFrameAxes(frame, mtx, dist, rvec, tvec, 0.02)
tvec, rvec = np.round(tvec, 7), np.round(rvec, 7)
# Display coordinates
x, y , z = tvec[0][0]*1000
cv2.putText(
frame,
f"Marker {marker_id}: X={x:.3f}m Y={y:.3f}m Z={z:.3f}m",
(10, 30),
cv2.FONT_HERSHEY_SIMPLEX,
0.6,
(0, 255, 0),
2
)
print(f"Marker {marker_id} coordinates: {x:.3f}, {y:.3f}, {z:.3f}")
obj_points = np.array([
[-marker_length / 2, marker_length / 2, 0],
[marker_length / 2, marker_length / 2, 0],
[marker_length / 2, -marker_length / 2, 0],
[-marker_length / 2, -marker_length / 2, 0]
])
imgpts, _ = cv2.projectPoints(obj_points, rvec, tvec, mtx, dist)
for pt in imgpts:
cv2.circle(frame, tuple(pt.ravel().astype(int)), 5, (0, 0, 255), -1)
cv2.imshow("Marker Pose", frame)
cv2.waitKey(5000)
#cv2.imshow("Marker Pose", frame)
# Convernt Camera to Base
Robot_Pose = robot.Pose()
R_flange = Robot_Pose.Rot33()
T_flange = np.array(Robot_Pose.Pos()) # mm
# --- Camera offset in flange coordinates ---
cam_offset_translation = np.array([0, 0,-100]) # mm from flange origin
cam_offset_rotation = np.eye(3) # adjust if tilted
# --- Flange → Camera transform ---
Pose_flange_to_cam = np.eye(4)
Pose_flange_to_cam[:3, :3] = cam_offset_rotation
Pose_flange_to_cam[:3, 3] = cam_offset_translation
# --- Base → Flange transform ---
Pose_base_to_flange = np.eye(4)
Pose_base_to_flange[:3, :3] = R_flange
Pose_base_to_flange[:3, 3] = T_flange
# --- Base → Camera transform ---
Pose_cam_in_robot = Pose_base_to_flange @ Pose_flange_to_cam
#Figure Out Object Position in Camera
# Convert ArUco to Camera Coordinates
#-------------------------------------------------
R_matrix, _ = cv2.Rodrigues(rvec)
tvec_mm = tvec.flatten()*1000 # meters → mm
rvec_aligned, R_aligned = align_z_up(rvec)
Pose_obj_in_cam = np.eye(4)
# 3. Build object pose in camera frame (4x4 matrix)
Pose_obj_in_cam[:3, :3] = R_aligned
# Returns a vector that the object is perpendicular to the camera.
Pose_obj_in_cam[:3, 3] = tvec_mm
#-------------------------------------------------
#Pose_obj_in_robot=Pose_cam_in_robot_rounded@Pose_obj_in_cam_rounded
Pose_obj_in_robot = np.matmul(Pose_cam_in_robot, Pose_obj_in_cam)
robot_pose_mat = Mat(Pose_obj_in_robot.tolist())
print("robot_pose_mat:",robot_pose_mat)
cv2.imshow("Marker Pose", frame)
robot.setSpeed(1000) # mm/s
robot.setAcceleration(1000) # mm/s²
# 🔹 Ensure the robot retains the current rotation while setting the new position
Marker_pose.setPose(robot_pose_mat)
robot.MoveJ(Marker_pose)
# Move the robot to the marker pose
robot.WaitMove()
exit()
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()