working version with two robots
This commit is contained in:
parent
280aee75ee
commit
c98760a2c7
|
@ -61,6 +61,26 @@ class Robot:
|
||||||
self.euler = None
|
self.euler = None
|
||||||
|
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
|
self.socket = socket.socket()
|
||||||
|
|
||||||
|
# variables for measurements
|
||||||
|
self.tms_0 = None
|
||||||
|
self.xm_0 = None
|
||||||
|
self.tms = None
|
||||||
|
self.xms = None
|
||||||
|
|
||||||
|
# currently active control
|
||||||
|
self.u1 = 0.0
|
||||||
|
self.u2 = 0.0
|
||||||
|
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
# connect to robot
|
||||||
|
try:
|
||||||
|
self.socket.connect((self.ip, 1234)) # connect to robot
|
||||||
|
except socket.error:
|
||||||
|
print("could not connect to socket")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
def f_ode(t, x, u):
|
def f_ode(t, x, u):
|
||||||
# dynamical model of the two-wheeled robot
|
# dynamical model of the two-wheeled robot
|
||||||
|
@ -89,9 +109,9 @@ class RemoteController:
|
||||||
|
|
||||||
self.anim_stopped = False
|
self.anim_stopped = False
|
||||||
|
|
||||||
#self.robots = [Robot(14, '192.168.1.103')]
|
self.robots = [Robot(11, '192.168.1.101'), Robot(14, '192.168.1.103')]
|
||||||
#self.robots = [Robot(15, '192.168.1.102')]
|
#self.robots = [Robot(15, '192.168.1.102')]
|
||||||
self.robots = [Robot(id, ip)]
|
#self.robots = [Robot(id, ip)]
|
||||||
|
|
||||||
self.robot_ids = {}
|
self.robot_ids = {}
|
||||||
for r in self.robots:
|
for r in self.robots:
|
||||||
|
@ -99,20 +119,13 @@ class RemoteController:
|
||||||
|
|
||||||
self.valid_cmds = ['forward', 'backward', 'turn left', 'turn right']
|
self.valid_cmds = ['forward', 'backward', 'turn left', 'turn right']
|
||||||
|
|
||||||
# connect to robot
|
|
||||||
self.rc_socket = socket.socket()
|
|
||||||
#self.rc_socket = None
|
|
||||||
try:
|
|
||||||
for r in self.robots:
|
|
||||||
self.rc_socket.connect((r.ip, 1234)) # connect to robot
|
|
||||||
except socket.error:
|
|
||||||
print("could not connect to socket")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# socket for movement commands
|
# socket for movement commands
|
||||||
self.comm_socket = socket.socket()
|
self.comm_socket = socket.socket()
|
||||||
self.comm_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
self.comm_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
|
||||||
|
for robot in self.robots:
|
||||||
|
robot.connect()
|
||||||
|
|
||||||
#self.comm_socket.bind((socket.gethostname(), 1337))
|
#self.comm_socket.bind((socket.gethostname(), 1337))
|
||||||
self.comm_socket.bind(('', 1337))
|
self.comm_socket.bind(('', 1337))
|
||||||
self.comm_socket.listen(5)
|
self.comm_socket.listen(5)
|
||||||
|
@ -124,11 +137,6 @@ class RemoteController:
|
||||||
self.ts = np.array([])
|
self.ts = np.array([])
|
||||||
self.xs = []
|
self.xs = []
|
||||||
|
|
||||||
# variables for measurements
|
|
||||||
self.tms_0 = None
|
|
||||||
self.xm_0 = None
|
|
||||||
self.tms = None
|
|
||||||
self.xms = None
|
|
||||||
|
|
||||||
# variable for mpc open loop
|
# variable for mpc open loop
|
||||||
self.ol_x = None
|
self.ol_x = None
|
||||||
|
@ -142,10 +150,6 @@ class RemoteController:
|
||||||
# pid parameters
|
# pid parameters
|
||||||
self.controlling = False
|
self.controlling = False
|
||||||
|
|
||||||
# currently active control
|
|
||||||
self.u1 = 0.0
|
|
||||||
self.u2 = 0.0
|
|
||||||
|
|
||||||
# animation
|
# animation
|
||||||
self.fig = plt.figure()
|
self.fig = plt.figure()
|
||||||
self.ax = self.fig.add_subplot(2,2,1)
|
self.ax = self.fig.add_subplot(2,2,1)
|
||||||
|
@ -187,7 +191,7 @@ class RemoteController:
|
||||||
# integrator
|
# integrator
|
||||||
self.r = scipy.integrate.ode(f_ode)
|
self.r = scipy.integrate.ode(f_ode)
|
||||||
self.omega_max = 5.0
|
self.omega_max = 5.0
|
||||||
self.control_scaling = 0.2
|
self.control_scaling = 0.3
|
||||||
#self.omega_max = 13.32
|
#self.omega_max = 13.32
|
||||||
|
|
||||||
|
|
||||||
|
@ -289,21 +293,21 @@ class RemoteController:
|
||||||
|
|
||||||
# save measured position and angle for plotting
|
# save measured position and angle for plotting
|
||||||
measurement = np.array([r.pos[0], r.pos[1], r.euler])
|
measurement = np.array([r.pos[0], r.pos[1], r.euler])
|
||||||
if self.tms_0 is None:
|
if r.tms_0 is None:
|
||||||
self.tms_0 = time.time()
|
r.tms_0 = time.time()
|
||||||
self.xm_0 = measurement
|
r.xm_0 = measurement
|
||||||
|
|
||||||
self.mutex.acquire()
|
self.mutex.acquire()
|
||||||
try:
|
try:
|
||||||
self.tms = np.array([0.0])
|
r.tms = np.array([0.0])
|
||||||
self.xms = measurement
|
r.xms = measurement
|
||||||
finally:
|
finally:
|
||||||
self.mutex.release()
|
self.mutex.release()
|
||||||
else:
|
else:
|
||||||
self.mutex.acquire()
|
self.mutex.acquire()
|
||||||
try:
|
try:
|
||||||
self.tms = np.vstack((self.tms, time.time() - self.tms_0))
|
r.tms = np.vstack((r.tms, time.time() - r.tms_0))
|
||||||
self.xms = np.vstack((self.xms, measurement))
|
r.xms = np.vstack((r.xms, measurement))
|
||||||
finally:
|
finally:
|
||||||
self.mutex.release()
|
self.mutex.release()
|
||||||
|
|
||||||
|
@ -388,8 +392,8 @@ class RemoteController:
|
||||||
self.t = time.time()
|
self.t = time.time()
|
||||||
elif event.key == pygame.K_DOWN:
|
elif event.key == pygame.K_DOWN:
|
||||||
self.controlling = False
|
self.controlling = False
|
||||||
if self.rc_socket:
|
if self.robot_ids[robot_id].socket:
|
||||||
self.rc_socket.send('(0.0,0.0)\n')
|
self.robot_ids[robot_id].socket.send('(0.0,0.0)\n')
|
||||||
elif event.key == pygame.K_0:
|
elif event.key == pygame.K_0:
|
||||||
self.target = np.array([0,0,0])
|
self.target = np.array([0,0,0])
|
||||||
elif event.key == pygame.K_PLUS:
|
elif event.key == pygame.K_PLUS:
|
||||||
|
@ -403,20 +407,20 @@ class RemoteController:
|
||||||
elif event.key == pygame.K_ESCAPE:
|
elif event.key == pygame.K_ESCAPE:
|
||||||
print("quit!")
|
print("quit!")
|
||||||
self.controlling = False
|
self.controlling = False
|
||||||
if self.rc_socket:
|
if self.robot_ids[robot_id].socket:
|
||||||
self.rc_socket.send('(0.0,0.0)\n')
|
self.robot_ids[robot_id].socket.send('(0.0,0.0)\n')
|
||||||
self.anim_stopped = True
|
self.anim_stopped = True
|
||||||
return
|
return
|
||||||
elif event.key == pygame.QUIT:
|
elif event.key == pygame.QUIT:
|
||||||
print("quit!")
|
print("quit!")
|
||||||
self.controlling = False
|
self.controlling = False
|
||||||
if self.rc_socket:
|
if self.robot_ids[robot_id].socket:
|
||||||
self.rc_socket.send('(0.0,0.0)\n')
|
self.robot_ids[robot_id].socket.send('(0.0,0.0)\n')
|
||||||
self.anim_stopped = True
|
self.anim_stopped = True
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.mpc:
|
if self.mpc:
|
||||||
x_pred = self.get_measurement_prediction()
|
x_pred = self.get_measurement_prediction(robot_id)
|
||||||
|
|
||||||
tmpc_start = time.time()
|
tmpc_start = time.time()
|
||||||
|
|
||||||
|
@ -424,9 +428,9 @@ class RemoteController:
|
||||||
angles_unwrapped = np.unwrap([x_pred[2], self.target[2]]) # unwrap angle to avoid jump in data
|
angles_unwrapped = np.unwrap([x_pred[2], self.target[2]]) # unwrap angle to avoid jump in data
|
||||||
error_ang = np.abs(angles_unwrapped[0] - angles_unwrapped[1])
|
error_ang = np.abs(angles_unwrapped[0] - angles_unwrapped[1])
|
||||||
#print("error pos = ", error_pos)
|
#print("error pos = ", error_pos)
|
||||||
print(" error_ang = {}, target = {}, angle = {}".format(error_ang, self.target[2], x_pred[2]))
|
print("error_pos = {}, error_ang = {}".format(error_pos, error_ang))
|
||||||
|
|
||||||
if error_pos > 0.1 or error_ang > 0.35:
|
if error_pos > 0.075 or error_ang > 0.35:
|
||||||
# solve mpc open loop problem
|
# solve mpc open loop problem
|
||||||
res = self.ols.solve(x_pred, self.target)
|
res = self.ols.solve(x_pred, self.target)
|
||||||
|
|
||||||
|
@ -461,28 +465,28 @@ class RemoteController:
|
||||||
for i in range(0, self.mstep): # option to use multistep mpc if len(range) > 1
|
for i in range(0, self.mstep): # option to use multistep mpc if len(range) > 1
|
||||||
u1 = us1[i]
|
u1 = us1[i]
|
||||||
u2 = us2[i]
|
u2 = us2[i]
|
||||||
if self.rc_socket:
|
if self.robot_ids[robot_id].socket:
|
||||||
self.rc_socket.send('({},{})\n'.format(u1, u2))
|
self.robot_ids[robot_id].socket.send('({},{})\n'.format(u1, u2))
|
||||||
if i < self.mstep:
|
if i < self.mstep:
|
||||||
time.sleep(self.dt)
|
time.sleep(self.dt)
|
||||||
self.t = time.time() # save time the most recent control was applied
|
self.t = time.time() # save time the most recent control was applied
|
||||||
|
|
||||||
|
|
||||||
def get_measurement_prediction(self):
|
def get_measurement_prediction(self, robot_id):
|
||||||
# get measurement
|
# get measurement
|
||||||
self.mutex.acquire()
|
self.mutex.acquire()
|
||||||
try:
|
try:
|
||||||
window = 3
|
window = 3
|
||||||
last_measurement = copy.deepcopy(self.xms[-window:])
|
last_measurement = copy.deepcopy(self.robot_ids[robot_id].xms[-window:])
|
||||||
#print("last_measurements = {}".format(last_measurement))
|
#print("last_measurements = {}".format(last_measurement))
|
||||||
#print("mean = {}".format(np.mean(last_measurement, axis=0)))
|
#print("mean = {}".format(np.mean(last_measurement, axis=0)))
|
||||||
last_measurement = np.mean(last_measurement, axis=0)
|
last_measurement = np.mean(last_measurement, axis=0)
|
||||||
last_time = copy.deepcopy(self.tms[-1])
|
last_time = copy.deepcopy(self.robot_ids[robot_id].tms[-1])
|
||||||
finally:
|
finally:
|
||||||
self.mutex.release()
|
self.mutex.release()
|
||||||
|
|
||||||
# prediction of state at time the mpc will terminate
|
# prediction of state at time the mpc will terminate
|
||||||
self.r.set_f_params(np.array([self.u1 * self.omega_max, self.u2 * self.omega_max]))
|
self.r.set_f_params(np.array([self.robot_ids[robot_id].u1 * self.omega_max, self.robot_ids[robot_id].u2 * self.omega_max]))
|
||||||
|
|
||||||
self.r.set_initial_value(last_measurement, last_time)
|
self.r.set_initial_value(last_measurement, last_time)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user