#!/usr/bin/env python3
import os
if "ROS_NAMESPACE" not in os.environ:
os.environ["ROS_NAMESPACE"] = "/robot1"
from unittest.mock import MagicMock
import matplotlib.pyplot as plt
import numpy as np
import rospy
import ruamel.yaml
from scipy.optimize import curve_fit
from soccer_common.transformation import Transformation
from soccer_common.utils import trimToPi, wrapToPi
from soccer_common.utils_rosparam import set_rosparam_from_yaml_file
robot_model = "bez2"
run_in_ros = False
[docs]def setup_calibration():
joint_state = MagicMock()
joint_state.position = [0.0] * 18
rospy.wait_for_message = MagicMock(return_value=joint_state)
[docs]def calibrate_x():
if not run_in_ros:
setup_calibration()
from soccer_pycontrol.navigator import Navigator
from soccer_pycontrol.navigator_ros import NavigatorRos
start_positions = []
final_positions = []
for x in np.linspace(0.0, 0.25, 26):
if run_in_ros:
walker = NavigatorRos(useCalibration=False)
else:
walker = Navigator(display=False, real_time=False, useCalibration=False)
walker.setPose(Transformation([0.0, 0, 0], [0, 0, 0, 1]))
walker.ready()
actual_start_position = walker.getPose()
goal_position = Transformation([x, 0, 0])
walker.setGoal(goal_position)
walk_success = walker.run(single_trajectory=True)
if not walk_success:
walker.close()
continue
final_position = walker.getPose()
final_transformation = final_position - actual_start_position
print(f"Final Transformation {final_transformation}")
start_positions.append(goal_position.position)
final_positions.append(final_transformation)
walker.close()
# Plot the beginning and final positions
x = np.array(start_positions)[:, 0]
y = np.array(final_positions)[:, 0]
plt.scatter(x, y, marker="+")
plt.title("X position vs Actual X position")
plt.xlabel("Desired X Position")
plt.ylabel("Actual X Position")
plt.grid(b=True, which="both", color="0.65", linestyle="-")
plt.minorticks_on()
def func(x, a, b):
return a * (x**2) + b * x
popt, pcov = curve_fit(func, x, y)
plt.plot(x, func(x, *popt), "r-", label="fit: a=%5.3f, b=%5.3f" % tuple(popt))
plt.show(block=False)
plt.waitforbuttonpress()
def func(x, a):
return a * x
fs = 8 # Final samples used to approximate linear fit after 0.25
popt2, pcov2 = curve_fit(func, x[-fs:] - x[-fs], y[-fs:] - y[-fs])
return popt[0], popt[1], popt2[0]
[docs]def calibrate_theta():
if not run_in_ros:
setup_calibration()
from soccer_pycontrol.navigator import Navigator
from soccer_pycontrol.navigator_ros import NavigatorRos
start_angles = []
final_angles = []
for theta in np.linspace(-np.pi / 2, np.pi / 2, 21):
if run_in_ros:
walker = NavigatorRos(useCalibration=False)
else:
walker = Navigator(display=False, real_time=False, useCalibration=False)
walker.setPose(Transformation([0.0, 0, 0], [0, 0, 0, 1]))
walker.ready()
actual_start_position = walker.getPose()
goal_position = Transformation([0, 0, 0], euler=[theta, 0, 0])
walker.setGoal(goal_position)
walk_success = walker.run(single_trajectory=True)
if not walk_success:
walker.close()
continue
final_position = walker.getPose()
final_transformation = final_position - actual_start_position
print(f"Final Transformation {final_transformation}")
start_angles.append(theta)
final_angles.append(final_transformation[2])
walker.wait(100)
walker.close()
# Plot the beginning and final positions
x = np.array(start_angles)
y = np.array(final_angles)
plt.scatter(x, y, marker="+")
plt.title("Theta vs Actual Theta position")
plt.xlabel("Desired Theta Position")
plt.ylabel("Actual Theta Position")
plt.grid(b=True, which="both", color="0.65", linestyle="-")
plt.minorticks_on()
def func(x, a):
return a * x
popt, pcov = curve_fit(func, x, y)
plt.plot(x, func(x, *popt), "r-", label="fit: a=%5.3f" % tuple(popt))
plt.show(block=False)
plt.waitforbuttonpress()
return popt[0]
if __name__ == "__main__":
if run_in_ros:
os.system(
"/bin/bash -c 'source /opt/ros/noetic/setup.bash && rosnode kill /robot1/soccer_strategy /robot1/soccer_pycontrol /robot1/soccer_trajectories'"
)
rospy.init_node("soccer_control_calibration")
rospy.loginfo("Initializing Soccer Control Calibration")
config_file_path = os.path.dirname(__file__).replace("src/soccer_pycontrol", f"config/{robot_model}_sim.yaml")
else:
config_file_path = os.path.dirname(__file__).replace("src/soccer_pycontrol", f"config/{robot_model}_sim_pybullet.yaml")
set_rosparam_from_yaml_file(param_path=config_file_path)
yaml = ruamel.yaml.YAML()
# Calibrate translation
a, b, a2 = calibrate_x()
with open(config_file_path) as f:
data = yaml.load(f)
data["calibration_trans_a"] = float(a)
data["calibration_trans_b"] = float(b)
data["calibration_trans_a2"] = float(a2)
with open(config_file_path, "w") as f:
yaml.dump(data, f)
# Calibrate rotation
a = calibrate_theta()
with open(config_file_path) as f:
data = yaml.load(f)
data["calibration_rot_a"] = float(a)
with open(config_file_path, "w") as f:
yaml.dump(data, f)