代码源码在gym\envs\classic_control\cartpole中
针对源码的详细解释都备注在下方代码块具体程序里
class CartPoleEnv (gym.Env)
- 初始化
def __init__(self):
self.gravity = 9.8
self.masscart = 1.0
self.masspole = 0.1
self.total_mass = (self.masspole + self.masscart)
self.length = 0.5 # actually half the pole's length
self.polemass_length = (self.masspole * self.length) # 力与力矩
self.force_mag = 10.0 #车的推力大小,表示平衡车向左或向右施加的力的幅度
self.tau = 0.02 # 状态更新的时间间隔 以秒为单位
# 阈值:超过此值表示任务失败
self.theta_threshold_radians = 12 * 2 * math.pi / 360 # 倒立摆的倾斜角阈值
self.x_threshold = 2.4 # 车的距离阈值
# Angle limit set to 2 * theta_threshold_radians so failing observation is still within bounds
# high为numpy数组,定义了观测空间的边界
# 观测空间定义了agent可以观察到的状态的范围
high = np.array([
self.x_threshold * 2, # 平衡车的位置维度 -x_threshold~x_threshold
np.finfo(np.float32).max, # 平衡车的速度维度 -∞~+∞
self.theta_threshold_radians * 2, # 倒立摆的角度纬度 -theta_threshold_radians
# ~ +theta_threshold_radians
np.finfo(np.float32).max]) # 倒立摆的角速度纬度 -∞~+∞
# 定义了动作空间,包含两个动作:0 和 1,别表示向左和向右的移动
self.action_space = spaces.Discrete(2)
# 定义了环境的观测空间。观测空间通常包含了智能体可以观察到的环境状态的范围
# box是一种数据类型,用来描述连续的多维数值空间
self.observation_space = spaces.Box(-high, high)
# 随机数生成器的种子
self._seed()
# 可视化工具
self.viewer = None
# 存储环境的当前中通,none表示当前状态尚未被定义
self.state = None
# 跟踪任务失败后的附加步骤数,当任务失败后,记录agent继续执行动作的步骤数
self.steps_beyond_done = None
- seed()函数
随机数生成器,以便在实验中获得可重复的结果
def _seed(self, seed=None):
self.np_random, seed = seeding.np_random(seed)
return [seed]
- step()函数
执行一个时间步(time step):
接受agent的动作、计算下一时刻状态和奖励、检查任务是否已完成
def _step(self, action):
# 确保agent执行的动作在允许的动作空间内,否则触发assert警告
assert self.action_space.contains(action), "%r (%s) invalid"%(action, type(action))
# 获取当前环境状态(x, x_dot, theta, theta_dot)
state = self.state
x, x_dot, theta, theta_dot = state
# 根据agent采取的动作确定平衡车的力的大小
# 基于平衡车和倒立摆的物理模型,更新状态s'=(x', x_dot', theta', theta_dot')
force = self.force_mag if action==1 else -self.force_mag
costheta = math.cos(theta)
sintheta = math.sin(theta)
temp = (force + self.polemass_length * theta_dot * theta_dot * sintheta) / self.total_mass
thetaacc = (self.gravity * sintheta - costheta* temp) / (self.length * (4.0/3.0 - self.masspole * costheta * costheta / self.total_mass))
xacc = temp - self.polemass_length * thetaacc * costheta / self.total_mass
x = x + self.tau * x_dot
x_dot = x_dot + self.tau * xacc
theta = theta + self.tau * theta_dot
theta_dot = theta_dot + self.tau * thetaacc
# 将刚计算出的新状态更新到环境中
self.state = (x,x_dot,theta,theta_dot)
# 检查任务是否完成,任务失败的条件是平衡车的位置或倒立摆角度超出阈值
done = x < -self.x_threshold \
or x > self.x_threshold \
or theta < -self.theta_threshold_radians \
or theta > self.theta_threshold_radians
done = bool(done) # 将done转化为布尔值:Ture or False
# 计算奖励值
# steps_beyond_done可以看作为标识符用来判断任务是在本次结束的还是在之前的时间步结束的
#情况1:任务还没完成,奖励1.0鼓励agent继续保持以完成任务
if not done:
reward = 1.0
#情况2:任务完成,且在当前时间步终止,奖励1.0
elif self.steps_beyond_done is None:
# Pole just fell!
self.steps_beyond_done = 0
reward = 1.0
#情况2:任务完成,但agent仍在继续采取动作,奖励0.0并记录警告日志
else:
if self.steps_beyond_done == 0:
logger.warning("You are calling 'step()' even though this environment has already returned done = True. You should always call 'reset()' once you receive 'done = True' -- any further steps are undefined behavior.") # 记录警告日志
self.steps_beyond_done += 1
reward = 0.0
# 最终step函数返回(s',r,done)以更新策略和价值函数,{}用于传递警告日志
return np.array(self.state), reward, done, {}
- reset()函数
当agent完成任务或任务失败后将环境重置为初始状态,以便进行新一轮训练
def _reset(self):
# 重置后的初始状态是在(-0.05,0.05)内均匀分布的随机数,size为状态总数
self.state = self.np_random.uniform(low=-0.05, high=0.05, size=(4,))
# 任务flag:表示尚未完成
self.steps_beyond_done = None
# 将state转化为numpy数组并返回
return np.array(self.state)
- render()函数
用于可视化环境状态,一般直接调用就行