机器人在环境中如何自主行驶呢?不同的机器人需要配置不同参数,差速或者其他动力学模型,如何获得更好的环境参数?
关于ROS、OpenAI和Gazebo已经测试过环境包括:
- Ubuntu 16.04 + ROS 1 Kinetic + OpenAI + Gazebo 7
- Ubuntu 18.04 + ROS 1 Melodic + OpenAI +Gazebo 9
了解OpenAI是什么?参考链接如下:
http://dota2.dj.sina.com.cn/2019-04-19/hvhiewr7123817.shtml
游戏场景,OpenAI已经“独孤求败”。那么相关算法如何应用于机器人操作系统ROS中呢?
Gazebo、Webots、V-Rep等仿真场景可以直接用OpenAI训练完成指定任务,现实机器人同样可以!
ROS官网参考教程:
http://wiki.ros.org/openai_ros
可以详细查阅。
之前,举过一个栗子,倒立摆,思考如下机器人,以turtlebot2为例吧:
100次训练
200次训练
机器人在环境中运动,依据运动情况进行训练,多次训练后(800次)如下:
分析规律,思考将其应用于mit-racecar:
使其自动行驶,并得到在此配置参数下速度的最大值?或求得单圈最小时间?
官方案例源码turtlebot2(Python):详细资料查看对应网址
#!/usr/bin/env python
import gym
from gym import wrappers
import gym_gazebo
import time
import numpy
import random
import time
import liveplot
import qlearn
def render():
render_skip = 0 #Skip first X episodes.
render_interval = 50 #Show render Every Y episodes.
render_episodes = 10 #Show Z episodes every rendering.
if (x%render_interval == 0) and (x != 0) and (x > render_skip):
env.render()
elif ((x-render_episodes)%render_interval == 0) and (x != 0) and (x > render_skip) and (render_episodes < x):
env.render(close=True)
if __name__ == '__main__':
env = gym.make('GazeboCircuitTurtlebotLidar-v0')
outdir = '/tmp/gazebo_gym_experiments'
env = gym.wrappers.Monitor(env, outdir, force=True)
plotter = liveplot.LivePlot(outdir)
last_time_steps = numpy.ndarray(0)
qlearn = qlearn.QLearn(actions=range(env.action_space.n),
alpha=0.1, gamma=0.8, epsilon=0.9)
initial_epsilon = qlearn.epsilon
epsilon_discount = 0.999 # 1098 eps to reach 0.1
start_time = time.time()
total_episodes = 10000
highest_reward = 0
for x in range(total_episodes):
done = False
cumulated_reward = 0 #Should going forward give more reward then L/R ?
observation = env.reset()
if qlearn.epsilon > 0.05:
qlearn.epsilon *= epsilon_discount
#render() #defined above, not env.render()
state = ''.join(map(str, observation))
for i in range(500):
# Pick an action based on the current state
action = qlearn.chooseAction(state)
# Execute the action and get feedback
observation, reward, done, info = env.step(action)
cumulated_reward += reward
if highest_reward < cumulated_reward:
highest_reward = cumulated_reward
nextState = ''.join(map(str, observation))
qlearn.learn(state, action, reward, nextState)
env._flush(force=True)
if not(done):
state = nextState
else:
last_time_steps = numpy.append(last_time_steps, [int(i + 1)])
break
if x % 100 == 0:
plotter.plot(env)
m, s = divmod(int(time.time() - start_time), 60)
h, m = divmod(m, 60)
print ("EP: "+str(x+1)+" - [alpha: "+str(round(qlearn.alpha,2))+" - gamma: "+str(round(qlearn.gamma,2))+" - epsilon: "+str(round(qlearn.epsilon,2))+"] - Reward: "+str(cumulated_reward)+" Time: %d:%02d:%02d" % (h, m, s))
#Github table content
print ("\n|"+str(total_episodes)+"|"+str(qlearn.alpha)+"|"+str(qlearn.gamma)+"|"+str(initial_epsilon)+"*"+str(epsilon_discount)+"|"+str(highest_reward)+"| PICTURE |")
l = last_time_steps.tolist()
l.sort()
#print("Parameters: a="+str)
print("Overall score: {:0.2f}".format(last_time_steps.mean()))
print("Best 100 score: {:0.2f}".format(reduce(lambda x, y: x + y, l[-100:]) / len(l[-100:])))
env.close()
官方案例源码erlerover(Python):详细资料查看对应网址
#!/usr/bin/env python
import gym
import gym_gazebo
import time
import numpy
import random
import time
import matplotlib
import matplotlib.pyplot as plt
class QLearn:
def __init__(self, actions, epsilon, alpha, gamma):
self.q = {}
self.epsilon = epsilon # exploration constant
self.alpha = alpha # discount constant
self.gamma = gamma # discount factor
self.actions = actions
def getQ(self, state, action):
return self.q.get((state, action), 0.0)
def learnQ(self, state, action, reward, value):
'''
Q-learning:
Q(s, a) += alpha * (reward(s,a) + max(Q(s') - Q(s,a))
'''
oldv = self.q.get((state, action), None)
if oldv is None:
self.q[(state, action)] = reward
else:
self.q[(state, action)] = oldv + self.alpha * (value - oldv)
def chooseAction(self, state, return_q=False):
q = [self.getQ(state, a) for a in self.actions]
maxQ = max(q)
if random.random() < self.epsilon:
minQ = min(q); mag = max(abs(minQ), abs(maxQ))
# add random values to all the actions, recalculate maxQ
q = [q[i] + random.random() * mag - .5 * mag for i in range(len(self.actions))]
maxQ = max(q)
count = q.count(maxQ)
# In case there're several state-action max values
# we select a random one among them
if count > 1:
best = [i for i in range(len(self.actions)) if q[i] == maxQ]
i = random.choice(best)
else:
i = q.index(maxQ)
action = self.actions[i]
if return_q: # if they want it, give it!
return action, q
return action
def learn(self, state1, action1, reward, state2):
maxqnew = max([self.getQ(state2, a) for a in self.actions])
self.learnQ(state1, action1, reward, reward + self.gamma*maxqnew)
class LivePlot(object):
def __init__(self, outdir, data_key='episode_rewards', line_color='blue'):
"""
Liveplot renders a graph of either episode_rewards or episode_lengths
Args:
outdir (outdir): Monitor output file location used to populate the graph
data_key (Optional[str]): The key in the json to graph (episode_rewards or episode_lengths).
line_color (Optional[dict]): Color of the plot.
"""
self.outdir = outdir
self._last_data = None
self.data_key = data_key
self.line_color = line_color
#styling options
matplotlib.rcParams['toolbar'] = 'None'
plt.style.use('ggplot')
plt.xlabel("")
plt.ylabel(data_key)
fig = plt.gcf().canvas.set_window_title('simulation_graph')
def plot(self):
results = gym.monitoring.monitor.load_results(self.outdir)
data = results[self.data_key]
#only update plot if data is different (plot calls are expensive)
if data != self._last_data:
self._last_data = data
plt.plot(data, color=self.line_color)
# pause so matplotlib will display
# may want to figure out matplotlib animation or use a different library in the future
plt.pause(0.000001)
def render():
render_skip = 0 #Skip first X episodes.
render_interval = 50 #Show render Every Y episodes.
render_episodes = 10 #Show Z episodes every rendering.
if (x%render_interval == 0) and (x != 0) and (x > render_skip):
env.render()
elif ((x-render_episodes)%render_interval == 0) and (x != 0) and (x > render_skip) and (render_episodes < x):
env.render(close=True)
if __name__ == '__main__':
env = gym.make('GazeboMazeErleRoverLidar-v0')
outdir = '/tmp/gazebo_gym_experiments'
env = gym.wrappers.Monitor(env, outdir, force=True)
#plotter = LivePlot(outdir)
last_time_steps = numpy.ndarray(0)
qlearn = QLearn(actions=range(env.action_space.n),
alpha=0.2, gamma=0.8, epsilon=0.9)
initial_epsilon = qlearn.epsilon
epsilon_discount = 0.9983
start_time = time.time()
total_episodes = 10000
highest_reward = 0
for x in range(total_episodes):
done = False
cumulated_reward = 0 #Should going forward give more reward then L/R ?
observation = env.reset()
if qlearn.epsilon > 0.05:
qlearn.epsilon *= epsilon_discount
#render() #defined above, not env.render()
state = ''.join(map(str, observation))
for i in range(1500):
# Pick an action based on the current state
action = qlearn.chooseAction(state)
# Execute the action and get feedback
observation, reward, done, info = env.step(action)
cumulated_reward += reward
if highest_reward < cumulated_reward:
highest_reward = cumulated_reward
nextState = ''.join(map(str, observation))
qlearn.learn(state, action, reward, nextState)
env._flush(force=True)
if not(done):
state = nextState
else:
last_time_steps = numpy.append(last_time_steps, [int(i + 1)])
break
#plotter.plot()
m, s = divmod(int(time.time() - start_time), 60)
h, m = divmod(m, 60)
print ("EP: "+str(x+1)+" - [alpha: "+str(round(qlearn.alpha,2))+" - gamma: "+str(round(qlearn.gamma,2))+" - epsilon: "+str(round(qlearn.epsilon,2))+"] - Reward: "+str(cumulated_reward)+" Time: %d:%02d:%02d" % (h, m, s))
#Github table content
print ("\n|"+str(total_episodes)+"|"+str(qlearn.alpha)+"|"+str(qlearn.gamma)+"|"+str(initial_epsilon)+"*"+str(epsilon_discount)+"|"+str(highest_reward)+"| PICTURE |")
l = last_time_steps.tolist()
l.sort()
#print("Parameters: a="+str)
print("Overall score: {:0.2f}".format(last_time_steps.mean()))
print("Best 100 score: {:0.2f}".format(reduce(lambda x, y: x + y, l[-100:]) / len(l[-100:])))
env.close()
引用网址: http://wiki.ros.org/openai_ros
部分机器翻译参考资料如下:
OpenAI提供了一套完整的强化学习库,可以对任务中的软件代理进行训练,因此代理可以自己学习如何最好地完成任务。主要类型的代理是软件代理,例如OpenAI团队训练智能体玩Dota 2的示例。
OpenAI集合库中最好的工具之一是Gym。Gym允许通过提供称为环境的共同点来比较强化学习算法。
不幸的是,即使Gym允许训练机器人,也不提供使用Gazebo模拟训练基于ROS的机器人的环境。
我们已经创建了openai_ros软件包以提供环境,因此我们所有的ROS机器人都有一个共同点,我们可以在训练机器人时比较我们最好的算法。该软件包是开源的,具有lGPL许可证。
该openai_ros包提供了组织需要从零创建你的机器人的训练,需要很少的执行一切共同的结构。它基本上由以下元素组成。
它包含将您的OpenAI程序连接到Gazebo 的GazeboEnvironment类。
它为最流行的基于ROS的机器人提供了一组已经制作的RobotEnvironments。该RobotEnvironments提供机器人的Gazebo模拟和OpenAI算法环境之间的完全整合,因此从机器人传感器获取的信息或发送行动,它是ROS trasnparent到OpenAI算法和你的开发者。
它提供了一组已经取得的TaskEnvironments,你可以与一起使用RobotEnvironments和GazeboEnvironment在定义的任务训练机器人TaskEnvironment。
它提供了一组模板来帮助您创建自己的RobotEnvironments和TasksEnvironments,它们直接连接到Gazebo(因为它们从GazeboEnvironment继承)
一般而言,图的结构可分为两大部分:
* 训练环境:培训环境将负责为您的学习算法提供所有需要的数据,以使机器人学习。他们继承了OpenAI Gym官方环境,因此他们完全兼容并使用Gym的正常训练程序。
有不同类型的训练环境:
任务环境。这是允许指定机器人必须学习的任务的类。
机器人环境。这是指定要在任务上使用的机器人的类。
Gazebo环境。这是指定与仿真模拟器连接的类。
通常,您不必触摸这些环境,只需使用提供的环境。在openai_ros包中,我们已经为机器人和任务提供了许多环境,因此您很可能只使用所需的环境并专注于学习算法。
如果您想使用未提供的机器人或不同的任务培训,您只需处理前两个类,以指定任务和/或机器人。该“ GazeboEnvironment”已经通过提供“openai_ros ”,你不必修改。
* 训练脚本:培训脚本将定义和设置您将要使用的学习算法,以便训练您的机器人。这通常是您的主要工作。
The Training Environments
训练环境是openai_ros包提供的Python类。
* 任务环境继承自Robot Environment。
* 机器人环境继承自Gazebo环境。
* Gazebo Environment继承自Gym Environment。Gym Environment(gym.Env)是OpenAI提供的最基本的环境结构。
Gazebo环境
The Gazebo Environment
正如我之前所说,Gazebo环境主要用于将模拟环境连接到Gazebo模拟器。例如,它在每个步骤之后处理模拟器的重置,或控制器的重置(如果需要),它还负责在进行训练步骤或模拟器时需要在模拟器上完成的所有步骤。训练重置(强化学习循环中的典型步骤)。
重要信息:此类是实现OpenAI Gym基础结构所需功能的类:
步进功能step function
种子功能seed function
重置功能reset function
关闭功能close function
但是,它调用子类函数(在RobotEnvironment和TaskEnvironment类上)来获取观察结果并应用操作。
本课程还会发布关于主题/openai/reward的最后一集奖励
无论如何,您需要了解的有关此环境的最重要的事情是,它对您来说是透明的。这意味着什么?嗯,这基本上意味着你不必担心它。无论机器人或您想要执行的火车类型如何,此环境始终都是相同的。因此,您不必更改它或为它工作。好消息,对吧?
此类是机器人和任务的独立
这个类的代码里面robot_gazebo_env.py中的openai_ros包(如果要修改的话)。
如果您想将此软件包与其他模拟器一起使用,那么您必须修改该类。
机器人环境
The Robot Environment
然后,机器人环境将包含与您要训练的特定机器人相关联的所有功能。这意味着,它将包含机器人控制所需的所有ROS功能。
该类还检查所需的每个ROS内容是否已在机器人上启动并运行(主题,服务...)。
在openai_ros包中,我们将为所有可用的ROS机器人提供RobotEnvironment,因此用户不必担心它,只需选择机器人并使用适当的RobotEnvironment类。
您只需要关心这个类,以防您想要将该软件包与您自己的机器人一起使用,只有您知道它。
目前可用的机器人环境:
* Cartpole
* Cube robot
* Hopper robot
* ROSbot by Husarion
* Wam by Barret
* Parrot drone
* Sawyer by Rethink robotics
* Shadow Robot Grasping Sandbox
* Summit XL by Robotnik
* Turtlebot2
* Turtlebot3 by Robotis
* WAMV water vehicle of the RobotX Challenge
更多机器人支持还在研发之中。
在Turtlebot 2示例中,这是由类处理turtlebot2_env.py所述的openai_ros包。
任务环境
The Task Environment
该任务环境类提供了我们想要的机器人学习任务中的所有内容。这取决于任务和机器人!。这意味着:
如果你想让同一个机器人学习另一个任务,那么你必须触摸它。也:
您可以不经修改地离开机器人环境和Gazebo环境
你将不得不对训练脚本做一个小模型
如果您希望其他机器人学习相同的任务,那么如果新机器人没有相同的界面,则可能还需要更改此类。
在迷宫示例中的Turtlebot2中,任务环境类在turtlebot2_maze.py文件中创建。
任务环境指定训练所需的以下内容:
如何将所选操作应用于机器人:function _set_action
如何获得动作产生的观察结果:function _get_obs
如何计算奖励:function _compute_reward
检测当前剧集的训练是否已完成:功能_is_done
此外,它还有一些用于处理模拟的功能:
function _init_env_variables:用于初始化每个剧集中需要设置回初始值的任何var
function _set_init_pose:用于初始化每集的机器人位置
注意:此处未定义培训步骤。这里只定义了如何在训练步骤中执行操作
每个机器人和任务都需要仿真模拟
The Simulations Needed for each Robot and Task
在OpenAI_ROS 的version2中,每个task_environment和robot_environment都有一个相关的启动文件。
这使得系统更简单,因为您现在不必担心下载与每个任务或机器人相关的模拟。它将在您的工作区中搜索它,如果没有,那么它将下载它。
此工作空间将由用户在启动主RL脚本时加载的yaml文件中定义,通过
参数名为ros_ws_abspath。查看教程以查看有关如何使用它的示例。
因此,当使用某个Envionment时,它将自动启动,您无需担心。您只能专注于培训脚本。
此训练脚本的目的是:
*设置您要使用的学习算法,以便让您的代理学习
*选择要使用的任务和机器人
您需要从训练脚本中了解的最重要的一点是,它完全独立于环境。这意味着,您可以在训练脚本中更改用于学习的算法,而无需担心修改环境结构。
可以在此处找到教程的所有代码: OpenAI_ROS_Examples-Git
本教程将通过让turtlebot2模拟学习如何导航简单的迷宫来向您介绍openai_ros。
本教程将教您如何通过几个简单的步骤,使用openai让您的Wam-V机器人学习如何进行InWaterTask 演示导航控制。