HJB方程的一些简单理解和过程推导
对于一个最优控制问题,HJB方程是连续时间最优控制的充分必要条件。
对于一个最优控制问题,HJB方程是连续时间最优控制的充分必要条件。
Hamilton-Jacobi-Bellman方程
如何理解HJB方程
−
∂
V
∂
t
(
x
(
t
)
,
t
)
=
min
u
(
t
)
∈
U
{
g
(
x
(
t
)
,
u
(
t
)
,
t
)
+
∂
V
∂
x
(
x
(
t
)
,
t
)
⋅
f
(
x
(
t
)
,
u
(
t
)
,
t
)
}
-\frac{ \partial V }{ \partial t }(x(t),t)=\mathop{\min}_{u(t)\in U}\left\{g(x(t),u(t),t)+\frac{ \partial V }{ \partial x }(x(t),t)\cdot f(x(t),u(t),t) \right\}
−∂t∂V(x(t),t)=minu(t)∈U{g(x(t),u(t),t)+∂x∂V(x(t),t)⋅f(x(t),u(t),t)}
其中
V
V
V是值函数,
g
g
g是过程成本,
f
f
f是状态方程
公式的理解
首先要理解值函数代表什么。值函数是性能指标(定义在下文)的最优值。一般性能指标都是由两部分组成,一部分是积分,一部分就是一个和终点有关的值。比如从A开车去B,那么积分的部分可以是油钱,这取决于你的控制方式和在这段时间的行驶距离。第二部分就是停止时离终点的距离。这里的油钱也被称为过程成本。控制(油门,刹车)用状态方程表示,给定当前位置和控制,就能知道下一时刻的位置在哪里。
这个式子有个隐含条件就是已知全程所用的时间。那么就是说在给定时间内,每一秒,都对应了应该用什么控制去走多少米。公式左边对应的是最优值随时间的变动,加负号是因为时间不能返流,满足因果关系。
现在看公式右边,第一项是当前所需要的油钱,第二项的偏导数说的是位置变动会引起最优值变动多少,那么具体移动多少移动到哪里是由状态方程决定的,那么第二项的意思就显而易见了,在当前位置,通过控制,实现移动后,能让最优值改变多少。位置变动引起油价和最优值的变动,而位置的变动是由控制引起的。我们希望寻找一个最优控制,这个最优控制能做到在最优值随时间变化过程中引起的变化正好是由于最优控制引起的位置的变化而导致的油价和最优值的变化,当然这个值是最小值。也可以理解成不浪费任何一秒的时间。
推导过程的步骤理解
我希望从上海出发到北京,有两条路可以走。一条是上海-南京-北京
,一条是上海-南京-天津-北京
。如果我们已知上海-南京-北京
是最短路径,那么从南京到北京的最短路径肯定是上海-南京-北京
的子序南京-北京
。
这里面我们将过程成本定义成油钱。如果一次性将上海-北京
这段距离最省钱的方式计算出来不容易,那么我们怎么办。首先我们可以先假设有那么一个最优值为
V
V
V,其等于油钱和离终点距离的总和。根据前一段的原理,可以先计算从上海-南京
的油钱,之后再计算从南京-北京
的,而且一定是最优的解。不如更极限一点,计算这一秒到下一秒的油钱,那么这一段的时间足够短,可以直接用当前的成本✖️时间来计算,或者说是当前的单位成本。之后的这么长距离的最优值是
V
‘
V^‘
V‘。那么这个1秒钟的油钱的成本,其实就是两个地方最优值的差。那么我们自然会想可能两个最优值之间就是有某种差值,那么用泰勒展开的方法对当前最优值在初始最优值位置进行展开,留下来的差值其实就是对应的油钱。那么按此过程理解,推导步骤基本就形成了。
从源头讲起
背景知识
最优控制问题
假设现在有一辆自动驾驶汽车,我们要设置控制方法,让其沿着指定路线到达某一个位置。要完成这项工作,首要的任务就是了解这辆车当前的“状态”和关于“控制”的变化规律:比如我们一般最关心当前的位置和车速,通过当前位置和速度去进行控制,比如打方向盘,踩刹车,踩油门等,从而又会引起当前位置和车速的变化。与此同时,我们可能还希望省油,车速平稳,不超速等要求。要满足以上的需求,需要合理的设计控制方法,以上问题我们就可以把它写成一个最优控制问题。
最优控制问题的四个基本元素:
-
状态方程:描述系统(自动驾驶汽车)的运动学或动力学方程
x ˙ ( t ) = f ( x ( t ) , u ( t ) , t ) , t ∈ [ t 0 , t f ] . x ( t 0 ) = x 0 \dot{x}(t)=f(x(t),u(t),t) , t\in[t_0,t_f]. x(t_0)=x_0 x˙(t)=f(x(t),u(t),t),t∈[t0,tf].x(t0)=x0
-
容许控制:控制与状态满足的约束
u ∈ U , x ∈ X . u\in U , x\in X. u∈U,x∈X.
-
目标集:在结束时间 t f t_f tf,被控对象的状态 x ( t f ) x(t_f) x(tf)应符合的条件
S = { x ( t f ) : m ( x ( t f ) , t f ) = 0 } S= \left\{ x(t_f):m(x(t_f),t_f)=0 \right\} S={x(tf):m(x(tf),tf)=0}
- 性能指标:
h
h
h为终端成本,
g
g
g为运行成本
J ( u ) = h ( x ( t f ) , t f ) + ∫ t 0 t f g ( x ( t ) , u ( t ) , t ) d t . \displaystyle{J(u)=h(x(t_f),t_f)+\int_{t_0}^{t_f}g(x(t),u(t),t)dt.} J(u)=h(x(tf),tf)+∫t0tfg(x(t),u(t),t)dt.
最优控制可以理解为求解满足状态方程、容许控制,且能达到目标点的情况下使性能指标最优的控制。
解决最优控制问题常用的有三种方法:变分法,极小值原理和动态规划。HJB方程就是在动态规划这个框架之中提出的。
动态规划的最优性原理
现在我希望从上海出发到北京,有两条路可以走。一条是上海-南京-北京
,一条是上海-南京-天津-北京
。这其实是一个多决策控制,我每到一个城市(状态),都需要做出决策,下一步去哪里(如何控制)。如果我们已知上海-南京-北京
是最短路径,那么从南京到北京的最短路径肯定是上海-南京-北京
的子序南京-北京
。
将上述过程抽象,就得到了著名的最优性原理:
多级决策过程的最优策略具有如下性质:不论初始状态和初始决策如何,其余的决策对于由初始决策所形成的状态来说,必定也是一个最优策略。
HJB方程
定义
现在考虑更为广泛的一类问题。以任意时刻为初始时刻,任意容许的状态为初始状态,同时定义性能指标为:
J
(
u
;
x
(
t
)
,
t
)
=
h
(
x
(
t
f
)
,
t
f
)
+
∫
t
t
f
g
(
x
(
τ
)
,
u
(
τ
)
,
τ
)
d
τ
.
\displaystyle{J(u;x(t),t)=h(x(t_f),t_f)+\int_{t}^{t_f}g(x(\tau),u(\tau),\tau)d\tau.}
J(u;x(t),t)=h(x(tf),tf)+∫ttfg(x(τ),u(τ),τ)dτ.
且其状态方程为:
x
˙
(
t
)
=
f
(
x
(
t
)
,
u
(
t
)
,
t
)
,
t
∈
[
t
0
,
t
f
]
\dot{x}(t)=f(x(t),u(t),t), t\in[t_0,t_f]
x˙(t)=f(x(t),u(t),t),t∈[t0,tf]
我们试图将求解这个性能指标问题转化为求解HJB方程问题,在此之前,要先定义该最优控制问题求解之后性能指标的最优值为值函数:
V
(
x
,
t
)
=
min
u
∈
U
J
(
u
;
x
,
t
)
,
t
∈
[
t
0
,
t
f
]
.
\displaystyle{V(x,t)=\mathop{\min}_{u\in U}J(u;x,t), t\in [t_0,t_f].}
V(x,t)=minu∈UJ(u;x,t),t∈[t0,tf].
那么我们所说的HJB方程如下:
−
∂
V
∂
t
(
x
(
t
)
,
t
)
=
min
u
(
t
)
∈
R
m
H
(
x
(
t
)
,
u
(
t
)
,
∂
V
∂
x
(
x
(
t
)
,
t
)
,
t
)
-\frac{ \partial V }{ \partial t }(x(t),t)=\mathop{\min}_{u(t)\in R^m}H(x(t),u(t),\frac{ \partial V }{ \partial x }(x(t),t),t)
−∂t∂V(x(t),t)=minu(t)∈RmH(x(t),u(t),∂x∂V(x(t),t),t)
满足的边界条件为:
V
(
x
(
t
f
)
,
t
f
)
=
h
(
x
(
t
f
)
,
t
f
)
V(x(t_f),t_f)=h(x(t_f),t_f)
V(x(tf),tf)=h(x(tf),tf)
其中 H ( x , u , p , t ) = g ( x , u , t ) + p ⋅ f ( x , u , t ) H(x,u,p,t)=g(x,u,t)+p\cdot f(x,u,t) H(x,u,p,t)=g(x,u,t)+p⋅f(x,u,t)为Hamiltonian函数。
这个公式看起来挺复杂,先看一下怎么用,再推导。
HJB方程的简单应用
这里给出一个例子,用于学会如何从一个给定的最优控制直接得出HJB方程:
比如性能指标中的过程指标(随便构造的,不具有任何意义)
g
(
u
,
x
)
=
1
2
(
u
(
t
)
u
m
a
x
)
2
+
x
(
t
)
x
r
e
f
\displaystyle{g(u,x)=\frac{1 }{2}(\frac{u(t) }{u_{max}})^2}+\frac{x(t) }{x_{ref}}
g(u,x)=21(umaxu(t))2+xrefx(t)
动力学方程为:
x
˙
(
t
)
=
u
(
t
)
\dot{x}(t)=u(t)
x˙(t)=u(t)
则对应的过程指标为:
J
(
u
;
x
(
t
)
,
t
)
=
h
(
x
(
t
f
)
,
t
f
)
+
∫
t
t
f
1
2
(
u
(
t
)
u
m
a
x
)
2
+
x
(
t
)
x
r
e
f
d
t
\displaystyle{J(u;x(t),t)=h(x(t_f),t_f)+\int_{t}^{t_f}\frac{1 }{2}(\frac{u(t) }{u_{max}})^2}+\frac{x(t) }{x_{ref}}dt
J(u;x(t),t)=h(x(tf),tf)+∫ttf21(umaxu(t))2+xrefx(t)dt
直接套用公式得出HJB方程为:
∂
V
∂
t
(
x
(
t
)
,
t
)
+
min
u
(
t
)
∈
R
m
(
1
2
(
u
(
t
)
u
m
a
x
)
2
+
x
(
t
)
x
r
e
f
+
u
(
t
)
⋅
∂
V
∂
x
)
\frac{ \partial V }{ \partial t }(x(t),t)+\mathop{\min}_{u(t)\in R^m}(\frac{1 }{2}(\frac{u(t) }{u_{max}})^2+\frac{x(t) }{x_{ref}}+u(t)\cdot \frac{ \partial V }{ \partial x })
∂t∂V(x(t),t)+minu(t)∈Rm(21(umaxu(t))2+xrefx(t)+u(t)⋅∂x∂V)
满足的边界条件为:
V
(
x
(
t
f
)
,
t
f
)
=
h
(
x
(
t
f
)
,
t
f
)
V(x(t_f),t_f)=h(x(t_f),t_f)
V(x(tf),tf)=h(x(tf),tf)
必要性的简要证明(公式推导)
选择一个小量
Δ
t
Δt
Δt,将
[
t
,
t
f
]
[t,t_f]
[t,tf]区间上最优控制的性能指标分为
[
t
,
t
+
Δ
t
]
[t,t+Δt]
[t,t+Δt]和
[
t
+
Δ
t
,
t
f
]
[t+Δt,t_f]
[t+Δt,tf]两段,其中
t
>
t
0
t>t_0
t>t0任取。值函数满足:
V
(
x
,
t
)
=
min
u
(
τ
)
:
[
t
,
t
f
]
→
R
m
{
h
(
x
(
t
f
)
,
t
f
)
+
∫
t
t
f
g
(
x
(
τ
)
,
u
(
τ
)
,
τ
)
d
τ
}
=
min
u
(
τ
)
:
[
t
,
t
f
]
→
R
m
{
h
(
x
(
t
f
)
,
t
f
)
+
∫
t
t
+
Δ
t
g
(
x
(
τ
)
,
u
(
τ
)
,
τ
)
d
τ
+
∫
t
+
Δ
t
t
f
g
(
x
(
τ
)
,
u
(
τ
)
,
τ
)
d
τ
}
\displaystyle{V(x,t)=\mathop{\min}_{u(\tau):[t,t_f]\rightarrow R^m}\left\{h(x(t_f),t_f)+\int_{t}^{t_f}g(x(\tau),u(\tau),\tau)d\tau\right\}}\\ \;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\; \displaystyle{=\mathop{\min}_{u(\tau):[t,t_f]\rightarrow R^m}\left\{h(x(t_f),t_f)+\int_{t}^{t+Δt}g(x(\tau),u(\tau),\tau)d\tau+ \int_{t+Δt}^{t_f}g(x(\tau),u(\tau),\tau)d\tau\right\}}
V(x,t)=minu(τ):[t,tf]→Rm{h(x(tf),tf)+∫ttfg(x(τ),u(τ),τ)dτ}=minu(τ):[t,tf]→Rm{h(x(tf),tf)+∫tt+Δtg(x(τ),u(τ),τ)dτ+∫t+Δttfg(x(τ),u(τ),τ)dτ}
考察区间
[
t
+
Δ
t
,
t
f
]
[t+Δt,t_f]
[t+Δt,tf]上的最优控制子问题。令该子问题的初始时刻为
t
+
Δ
t
t+Δt
t+Δt,初始状态为
x
(
t
+
Δ
t
)
x(t+Δt)
x(t+Δt)。其值函数为:
V
(
x
(
t
+
Δ
t
)
,
t
+
Δ
t
)
=
min
u
(
τ
)
:
[
t
+
Δ
t
,
t
f
]
→
R
m
{
h
(
x
(
t
f
)
,
t
f
)
+
∫
t
+
Δ
t
t
f
g
(
x
(
τ
)
,
u
(
τ
)
,
τ
)
d
τ
}
\displaystyle{V(x(t+Δt),t+Δt)=\mathop{\min}_{u(\tau):[t+Δt,t_f]\rightarrow R^m}\left\{h(x(t_f),t_f)+\int_{t+Δt}^{t_f}g(x(\tau),u(\tau),\tau)d\tau\right\}}
V(x(t+Δt),t+Δt)=minu(τ):[t+Δt,tf]→Rm{h(x(tf),tf)+∫t+Δttfg(x(τ),u(τ),τ)dτ}
根据最优性原理,如果
u
(
τ
)
:
[
t
,
t
f
]
→
R
m
u(\tau):[t,t_f]\rightarrow R^m
u(τ):[t,tf]→Rm是
[
t
,
t
f
]
[t,t_f]
[t,tf]上的最优控制,在子区间
[
t
+
Δ
t
,
t
f
]
[t+Δt,t_f]
[t+Δt,tf]上
u
(
τ
)
:
[
t
+
Δ
t
,
t
f
]
→
R
m
u(\tau):[t+Δt,t_f]\rightarrow R^m
u(τ):[t+Δt,tf]→Rm也是子问题的最优控制。所以有:
V
(
x
(
t
)
,
t
)
=
min
u
(
τ
)
:
[
t
,
t
+
Δ
t
]
→
R
m
{
∫
t
t
+
Δ
t
g
(
x
(
τ
)
,
u
(
τ
)
,
τ
)
d
τ
+
V
(
x
(
t
+
Δ
t
)
,
t
+
Δ
t
)
}
\displaystyle{V(x(t),t)=\mathop{\min}_{u(\tau):[t,t+Δt]\rightarrow R^m}\left\{\int_{t}^{t+Δt}g(x(\tau),u(\tau),\tau)d\tau+V(x(t+Δt),t+Δt)\right\}}
V(x(t),t)=minu(τ):[t,t+Δt]→Rm{∫tt+Δtg(x(τ),u(τ),τ)dτ+V(x(t+Δt),t+Δt)}
将
t
+
Δ
t
t+Δt
t+Δt时刻的值函数
V
(
x
(
t
+
Δ
t
)
,
t
+
Δ
t
)
V(x(t+Δt),t+Δt)
V(x(t+Δt),t+Δt)在x(t),t点一阶泰勒展开,得到
V
(
x
(
t
)
,
t
)
=
min
u
(
τ
)
:
[
t
,
t
+
Δ
t
]
→
R
m
{
∫
t
t
+
Δ
t
g
(
x
(
τ
)
,
u
(
τ
)
,
τ
)
d
τ
+
V
(
x
(
t
+
Δ
t
)
,
t
+
Δ
t
)
}
=
min
u
(
τ
)
:
[
t
,
t
+
Δ
t
]
→
R
m
{
∫
t
t
+
Δ
t
g
(
x
(
τ
)
,
u
(
τ
)
,
τ
)
d
τ
+
V
(
x
(
t
)
,
t
)
+
∂
V
∂
t
(
x
(
t
)
,
t
)
Δ
t
+
∂
V
∂
x
(
x
(
t
)
,
t
)
⋅
[
x
(
t
+
Δ
t
)
−
x
(
t
)
]
+
o
(
Δ
t
)
}
\displaystyle{V(x(t),t)=\mathop{\min}_{u(\tau):[t,t+Δt]\rightarrow R^m}\left\{\int_{t}^{t+Δt}g(x(\tau),u(\tau),\tau)d\tau+V(x(t+Δt),t+Δt)\right\}}\\ \quad\quad\quad\quad\quad \displaystyle{=\mathop{\min}_{u(\tau):[t,t+Δt]\rightarrow R^m}\left\{\int_{t}^{t+Δt}g(x(\tau),u(\tau),\tau)d\tau+V(x(t),t)+\frac{ \partial V }{ \partial t }(x(t),t)Δt+\frac{ \partial V }{ \partial x }(x(t),t)\cdot [x(t+Δt)-x(t)]+o(Δt) \right\}}
V(x(t),t)=minu(τ):[t,t+Δt]→Rm{∫tt+Δtg(x(τ),u(τ),τ)dτ+V(x(t+Δt),t+Δt)}=minu(τ):[t,t+Δt]→Rm{∫tt+Δtg(x(τ),u(τ),τ)dτ+V(x(t),t)+∂t∂V(x(t),t)Δt+∂x∂V(x(t),t)⋅[x(t+Δt)−x(t)]+o(Δt)}
对上式简化。对足够小的
Δ
t
,
τ
∈
[
t
,
t
+
Δ
t
]
,
g
Δt,\tau\in[t,t+Δt],g
Δt,τ∈[t,t+Δt],g对t连续,于是有:
∫
t
t
+
Δ
t
g
(
x
(
τ
)
,
u
(
τ
)
,
τ
)
d
τ
=
g
(
x
(
t
)
,
u
(
t
)
,
t
)
Δ
t
+
o
(
Δ
t
)
∂
V
∂
x
(
x
(
t
)
,
t
)
⋅
[
x
(
t
+
Δ
t
)
−
x
(
t
)
]
=
∂
V
∂
x
(
x
(
t
)
,
t
)
⋅
f
(
x
(
t
)
,
u
(
t
)
,
t
)
Δ
t
+
o
(
Δ
t
)
\int_{t}^{t+Δt}g(x(\tau),u(\tau),\tau)d\tau=g(x(t),u(t),t)Δt+o(Δt)\\ \frac{ \partial V }{ \partial x }(x(t),t)\cdot [x(t+Δt)-x(t)]=\frac{ \partial V }{ \partial x }(x(t),t)\cdot f(x(t),u(t),t)Δt+o(Δt)
∫tt+Δtg(x(τ),u(τ),τ)dτ=g(x(t),u(t),t)Δt+o(Δt)∂x∂V(x(t),t)⋅[x(t+Δt)−x(t)]=∂x∂V(x(t),t)⋅f(x(t),u(t),t)Δt+o(Δt)
于是又可以得到:
V
(
x
(
t
)
,
t
)
=
min
u
(
τ
)
:
[
t
,
t
+
Δ
t
]
→
R
m
{
g
(
x
(
t
)
,
u
(
t
)
,
t
)
Δ
t
+
V
(
x
(
t
)
,
t
)
+
∂
V
∂
t
(
x
(
t
)
,
t
)
Δ
t
+
∂
V
∂
x
(
x
(
t
)
,
t
)
⋅
f
(
x
(
t
)
,
u
(
t
)
,
t
)
Δ
t
+
o
(
Δ
t
)
}
\displaystyle{V(x(t),t)=\mathop{\min}_{u(\tau):[t,t+Δt]\rightarrow R^m}\left\{g(x(t),u(t),t)Δt+V(x(t),t)+\frac{ \partial V }{ \partial t }(x(t),t)Δt+\frac{ \partial V }{ \partial x }(x(t),t)\cdot f(x(t),u(t),t)Δt+o(Δt) \right\}}
V(x(t),t)=minu(τ):[t,t+Δt]→Rm{g(x(t),u(t),t)Δt+V(x(t),t)+∂t∂V(x(t),t)Δt+∂x∂V(x(t),t)⋅f(x(t),u(t),t)Δt+o(Δt)}
这里面可以看到优化的是
u
u
u所以左右的
V
(
x
(
t
)
,
t
)
V(x(t),t)
V(x(t),t)可以删掉,移向整理得:
−
∂
V
∂
t
(
x
(
t
)
,
t
)
Δ
t
=
min
u
(
τ
)
:
[
t
,
t
+
Δ
t
]
→
R
m
{
g
(
x
(
t
)
,
u
(
t
)
,
t
)
Δ
t
+
∂
V
∂
x
(
x
(
t
)
,
t
)
⋅
f
(
x
(
t
)
,
u
(
t
)
,
t
)
Δ
t
+
o
(
Δ
t
)
}
-\frac{ \partial V }{ \partial t }(x(t),t)Δt=\mathop{\min}_{u(\tau):[t,t+Δt]\rightarrow R^m}\left\{g(x(t),u(t),t)Δt+\frac{ \partial V }{ \partial x }(x(t),t)\cdot f(x(t),u(t),t)Δt+o(Δt) \right\}
−∂t∂V(x(t),t)Δt=minu(τ):[t,t+Δt]→Rm{g(x(t),u(t),t)Δt+∂x∂V(x(t),t)⋅f(x(t),u(t),t)Δt+o(Δt)}
同时除以
Δ
t
Δt
Δt,再令
Δ
t
→
0
Δt\rightarrow0
Δt→0.得到对于任意的
t
∈
[
t
0
,
t
f
]
t\in[t_0,t_f]
t∈[t0,tf]都有:
−
∂
V
∂
t
(
x
(
t
)
,
t
)
=
min
u
(
t
)
∈
U
{
g
(
x
(
t
)
,
u
(
t
)
,
t
)
+
∂
V
∂
x
(
x
(
t
)
,
t
)
⋅
f
(
x
(
t
)
,
u
(
t
)
,
t
)
}
-\frac{ \partial V }{ \partial t }(x(t),t)=\mathop{\min}_{u(t)\in U}\left\{g(x(t),u(t),t)+\frac{ \partial V }{ \partial x }(x(t),t)\cdot f(x(t),u(t),t) \right\}
−∂t∂V(x(t),t)=minu(t)∈U{g(x(t),u(t),t)+∂x∂V(x(t),t)⋅f(x(t),u(t),t)}
这样就得到了HJB方程,
t
∈
[
t
0
,
t
f
]
t\in[t_0,t_f]
t∈[t0,tf]
−
∂
V
∂
t
(
x
(
t
)
,
t
)
=
min
u
(
t
)
∈
U
H
(
x
(
t
)
,
u
(
t
)
,
∂
V
∂
x
(
x
(
t
)
,
t
)
,
t
)
-\frac{ \partial V }{ \partial t }(x(t),t)=\mathop{\min}_{u(t)\in U}H(x(t),u(t),\frac{ \partial V }{ \partial x }(x(t),t),t)
−∂t∂V(x(t),t)=minu(t)∈UH(x(t),u(t),∂x∂V(x(t),t),t)
性能指标中,令
t
=
t
f
t=t_f
t=tf,即可得到边界条件
V
(
x
(
t
f
)
,
t
f
)
=
h
(
x
(
t
f
)
,
t
f
)
V(x(t_f),t_f)=h(x(t_f),t_f)
V(x(tf),tf)=h(x(tf),tf)
证毕
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)