- 2025-03-09
-
回复了主题帖:
【新年花灯秀】彩色PCB雪花灯
漂亮
- 2025-03-01
-
回复了主题帖:
想知道两轮差速方形底盘 URDF 咋做,ROS2 配 Rviz 咋显示吗?看这里!
学习学习
- 2025-02-28
-
回复了主题帖:
跟我学:每天5分钟,一个月入门mujoco(序)
freebsder 发表于 2025-2-28 16:29
这是个仿真平台还是个开发平台呢?
可以把这个当作是一个游戏引擎:把一个完整游戏里面的素材都删掉,但保留了接口。
就像马里奥制造那样的,各种砖块都放在那里,你想搭一个什么关卡都可以,等你搭好了,就可以尝试过关(类似仿真),但是你也可以你的存档给别人,别人可以在你基础上继续修改(类似开发)。
- 2025-02-27
-
回复了主题帖:
跟我学:每天5分钟,一个月入门mujoco(1.3)
jryq213 发表于 2025-2-27 12:33
非常错的资料,学习了,如果有详细课件更好。
有源码,全套代码我是我自己敲的。
需要ppt么?那可能得重新写
-
回复了主题帖:
跟我学:每天5分钟,一个月入门mujoco(1.3)
wangerxian 发表于 2025-2-27 08:57
可以配置小球的密度或者材质吗?
可以的,下下下……节就有了
下节是初速度
下下节是采集数据和生成曲线
再往后就是改变各种外部参数,比如重力、风力(风阻)、密度等等
- 2025-02-26
-
发表了主题帖:
跟我学:每天5分钟,一个月入门mujoco(1.3)
第3节 自由落体
在以比萨斜塔为背景,让两个小球从高处落下:
[localvideo]f194ab1f63194a35a1dd18fae011e4a6[/localvideo]
可以看到,存在一个加速下落的过程。
代码如下:
import mujoco
import mujoco.viewer
import time
from xml.dom import minidom
def load_xml(xml):
dom = minidom.parse(xml)
return dom
def get_root_element(dom):
if dom is not None:
root = dom.documentElement
return root
return None
def get_child_elements(root,tag):
if root is not None:
child_elements = root.getElementsByTagName(tag)
return child_elements
return None
def make_object(dom,obj):
newnode = dom.createElement("geom")
for k,v in obj.items():
newnode.setAttribute(k,v)
return newnode
def add_object(dom,pnode,newnode):
if newnode.nodeName == "geom":
tmpbody = dom.createElement("body")
tmpnode = dom.createElement("joint")
tmpnode.setAttribute("type","free")
tmpbody.appendChild(tmpnode)
tmpbody.appendChild(newnode)
pnode.appendChild(tmpbody)
if __name__ == "__main__":
red_ball = {}
red_ball["type"] = "sphere"
red_ball["pos"] = "16 -1.5 30"
red_ball["size"] = "1"
red_ball["rgba"] = ".9 0 0 1"
blue_ball = {}
blue_ball["type"] = "sphere"
blue_ball["pos"] = "16 1.5 30"
blue_ball["size"] = "1"
blue_ball["rgba"] = "0 0 .9 1"
dom = load_xml("tower.xml")
root = get_root_element(dom)
pnode = get_child_elements(root, 'worldbody')[0]
newnode = make_object(dom,red_ball)
add_object(dom,pnode,newnode)
newnode = make_object(dom,blue_ball)
add_object(dom,pnode,newnode)
model = mujoco.MjModel.from_xml_string(dom.toxml())
data = mujoco.MjData(model)
viewer = mujoco.viewer.launch_passive(model, data)
viewer.cam.azimuth = 145.0
viewer.cam.distance = 90
viewer.cam.elevation = -5.0
while True:
mujoco.mj_step(model, data)
viewer.sync()
time.sleep(0.001)
分析:
这里有两个函数
def make_object(dom,obj):
newnode = dom.createElement("geom")
for k,v in obj.items():
newnode.setAttribute(k,v)
return newnode
def add_object(dom,pnode,newnode):
if newnode.nodeName == "geom":
tmpbody = dom.createElement("body")
tmpnode = dom.createElement("joint")
tmpnode.setAttribute("type","free")
tmpbody.appendChild(tmpnode)
tmpbody.appendChild(newnode)
pnode.appendChild(tmpbody)
make_object是用于生成一个新的geom(几何体),是将刚生成的几何体放置在之前的dom中。
在前面章节里面,我们知道,如果不做设置,同一个body内的的几何体相对位置是固定的,也就是说,即使我们放置了geom,它也会悬在半空。为了实现下落的要求,我们增加了一个属性类型为”free”的joint(关节),这里新引入了joint的概念,它是用于连接几何体的虚拟构件。主要属性有:
name:名字
pos:关节位置
type:关节类型,可以是hinge(铰链关节,绕单一轴旋转)、slide(滑动关节,沿单一轴线移动)、ball(球形关节)、free(自由型),缺省是hinge
axis:轴,可以用于滚动(hinge)或者滑动slide
- 2025-02-25
-
回复了主题帖:
跟我学:每天5分钟,一个月入门mujoco(1.2)
wangerxian 发表于 2025-2-25 20:39
这是一个3D库吗?可以导入什么样的3D文件?
事实上,它的3D功能好像还真不怎么样,基础功能只有方块、球、椭球、连三角块都需要外部建模,支持stl格式的mesh导入……
而且渲染功能我一直没搞定,但物理特性仿真不错(特指固体)。
- 2025-02-24
-
发表了主题帖:
跟我学:每天5分钟,一个月入门mujoco(1.2)
第2节 设置视角
在前1节,我们建立了模型并且将其存储为一个xml文件,但我们发现,这个模型相对我们的显示界面“太大”了,需要用鼠标调整以后才能摆在屏幕中间,至于怎么调整,相信大家都很熟悉,左键拖动旋转,右键移动位置,滚轮缩放。
在本节,我们复习载入xml文件,并学习在代码中变换视角。
[localvideo]67a900b20b8bda66810078b99025e377[/localvideo]
代码其实非常简单,就是不断变换几个参数:
import mujoco
import mujoco.viewer
import time
if __name__ == "__main__":
model = mujoco.MjModel.from_xml_path('tower.xml')
data = mujoco.MjData(model)
viewer = mujoco.viewer.launch_passive(model, data)
for i in range(0,960):
viewer.cam.elevation= 0 - i/65
viewer.cam.distance = i/15+40
viewer.cam.azimuth = i/2
viewer.cam.lookat = [0, 0, -15+i/55]
time.sleep(0.02)
由于代码实在太简单,本节不做代码讲解。
-
回复了主题帖:
跟我学:每天5分钟,一个月入门mujoco(1.1)
hellokitty_bean 发表于 2025-2-24 08:57
让人好好奇呀。。。。。。。。。。mujoco这么可爱好玩吗
如果当游戏玩的话,建议“马里奥制造”,如果想用来当物理学教具,我认为初中的所有实验都够了
- 2025-02-23
-
发表了主题帖:
跟我学:每天5分钟,一个月入门mujoco(1.1)
重力加速度
在本章中,我们尝试编写一个模型测试物体在重力场中的行为,并尝试修改各项参数(质量、形状、重力加速度等),看看如何在mujoco的呈现。
第1节 坐标系与参照物
说起重力加速度,最出名的肯定是伽利略先生在比萨斜塔上做的自由落体实验。多年前我也曾前往斜塔朝圣,这里就以斜塔作为落体的参照物吧。
这一节我们先学着画参照物:
(照片来自网络,侵权请告知)
可以看到塔分8层,每层的结构相似,由柱子和塔身构成,可以抽象为使用若干大大小小的圆柱组合而成。
如前一章节中介绍,可以使用xml格式文件来存储mujoco模型。那么现在就介绍一下mujoco里面常用的xml标签元素:
mujoco:
这是最外层的标签元素,也就是所谓的根,全xml只能有一个,有属性值model,缺省是“MuJoCo Model”,在viewer中显示的标题。
body(体):
body是在mujoco中用于指定物体的标签元素(支持套嵌,最外层的叫做worldbody),可以包括的属性有:
name:体的名字,定义后可以用name来引用这个体
pos:体的位置,当然是基于上级元素的,缺省是(0,0,0)
euler:控制体的方向,也是基于上级元素的
Geom(几何体):
name:名字
pos:几何体位置
type:几何体类型,可以是sphere(球体,缺省值)、plane(地平面)、box(立方体)、cylinder(圆柱体)、capsule(胶囊体)、ellipsoid(橄榄球形)等等
size:几何体大小
rgba:渲染几何体的颜色
知道了上述信息,就能开始了,首先,我们具有简单python基础,编写xml文件可以用dom。
import mujoco
import mujoco.viewer
import xml.dom.minidom as minidom
import math
def create_root(dom):
root = dom.documentElement
root.setAttribute("model", "Elizabeth Tower")
return root
def create_world(dom,root):
worldbody = dom.createElement("worldbody")
root.appendChild(worldbody)
plane = dom.createElement("geom")
plane.setAttribute("type","plane")
plane.setAttribute("size","20 20 0.1")
plane.setAttribute("rgba","0 .8 0 1")
plane.setAttribute("pos","0 0 -22")
ground = dom.createElement("geom")
ground.setAttribute("type","box")
ground.setAttribute("name","ground")
ground.setAttribute("size","20 20 1")
ground.setAttribute("rgba",".237 .189 .101 1")
ground.setAttribute("pos","0 0 -23")
worldbody.appendChild(plane)
worldbody.appendChild(ground)
towerbody = create_tower(dom)
towerbody.setAttribute("pos","0 0 -23")
towerbody.setAttribute("euler","0 5 0")
worldbody.appendChild(towerbody)
def create_tower(dom):
towerbody = dom.createElement("body")
towerbody.setAttribute("name","Elizabeth Tower")
towerbase = dom.createElement("geom")
towerbase.setAttribute("type","cylinder")
towerbase.setAttribute("rgba",".5 .5 .5 1")
towerbase.setAttribute("pos","0 0 5")
towerbase.setAttribute("size","9 5")
towerbody.appendChild(towerbase)
for i in range(15):
a=11
pole = dom.createElement("geom")
pole.setAttribute("type","cylinder")
pole.setAttribute("rgba",".5 .5 .5 1")
pole.setAttribute("pos",str(a*math.sin(i*math.pi/7.5))+" "+str(a*math.cos(i*math.pi/7.5))+" 5")
pole.setAttribute("size",".7 5")
towerbody.appendChild(pole)
top1 = dom.createElement("geom")
top1.setAttribute("type","cylinder")
top1.setAttribute("rgba",".5 .5 .5 1")
top1.setAttribute("pos","0 0 10")
top1.setAttribute("size","12.1 .1")
towerbody.appendChild(top1)
a = 10.8
for level in range(1,7):
top = dom.createElement("geom")
top.setAttribute("type","cylinder")
top.setAttribute("rgba",".5 .5 .5 1")
top.setAttribute("pos","0 0 "+str(10+level*6))
top.setAttribute("size",str(a+0.8)+" .1")
towerbody.appendChild(top)
for i in range(30):
pole = dom.createElement("geom")
pole.setAttribute("type","cylinder")
pole.setAttribute("rgba",".5 .5 .5 1")
pole.setAttribute("pos",str(a*math.sin(i*math.pi/15))+" "+str(a*math.cos(i*math.pi/15))+" "+str(7+6*level))
pole.setAttribute("size",".5 3")
towerbody.appendChild(pole)
stair = dom.createElement("geom")
stair.setAttribute("type","cylinder")
stair.setAttribute("rgba",".5 .5 .5 0.5")
stair.setAttribute("pos","0 0 "+str(7+6*level))
stair.setAttribute("size",str(a-2)+" 3")
towerbody.appendChild(stair)
a=a-0.15
towertop = dom.createElement("geom")
towertop.setAttribute("type","cylinder")
towertop.setAttribute("rgba",".5 .5 .5 1")
towertop.setAttribute("pos","0 0 50")
towertop.setAttribute("size","7 4")
towerbody.appendChild(towertop)
for i in range(12):
a=8
pole = dom.createElement("geom")
pole.setAttribute("type","cylinder")
pole.setAttribute("rgba",".5 .5 .5 1")
pole.setAttribute("pos",str(a*math.sin(i*math.pi/6))+" "+str(a*math.cos(i*math.pi/6))+" 50")
pole.setAttribute("size",".4 4")
towerbody.appendChild(pole)
top2 = dom.createElement("geom")
top2.setAttribute("type","cylinder")
top2.setAttribute("rgba",".5 .5 .5 1")
top2.setAttribute("pos","0 0 54")
top2.setAttribute("size","9 .3")
towerbody.appendChild(top2)
return towerbody
if __name__ == "__main__":
dom = minidom.getDOMImplementation().createDocument(None,"mujoco",None)
root = create_root(dom)
create_world(dom,root)
m = mujoco.MjModel.from_xml_string(dom.toxml())
v = mujoco.viewer.launch(m)
with open('tower.xml', 'w', encoding='utf-8') as f:
dom.writexml(f, addindent='\t', newl='\n',encoding='utf-8')
执行一下看看,嗯,由于模型太大了,可能看不到全图,可以用鼠标滚轮操作一下缩放:
代码分析:
dom = minidom.getDOMImplementation().createDocument(None,"mujoco",None)
新建dom,其中根叫做mujoco
root = dom.documentElement
root.setAttribute("model", "Elizabeth Tower")
获取根节点,指定model属性(显示名为Elizabeth Tower)。
worldbody = dom.createElement("worldbody")
root.appendChild(worldbody)
在root下增加worldbody。
with open('tower.xml', 'w', encoding='utf-8') as f:
dom.writexml(f, addindent='\t', newl='\n',encoding='utf-8')
保存xml文件,命名为tower.xml。
- 2025-02-21
-
回复了主题帖:
恭喜LitchiCheng走马上任机器人开发版块版主!!
恭喜恭喜
-
发表了主题帖:
跟我学:每天5分钟,一个月入门mujoco(序)
机器人仿真是一个很有趣的话题,多年前我曾尝试用过不少游戏引擎去学习“制作”机器人,但最终比较倾向于使用webots和mujoco。
这里可以开两个两个讨论话题:webots、mujoco。
Mujoco也是比较神奇的,最初免费,不少人学习使用;后来收费,损失了大量人气,再后来被deepmind买下,直接开源了,但已经不复当年盛况,在中文的各论坛上也基本找不到什么新一点有深度的资料——几年前的还有,但已经不再适配最新版本了。
有鉴于此,笔者准备为爱发电,借eeworld宝地开一个mujoco系列。大家可以试着跟读,每天只占用5分钟阅读时间,大概一个月,就能把这个有趣物理引擎玩转了。当然我不保证每天都能更新。
mujoco是什么?
Multi-Joint dynamics with Contact,翻译起来可以认为是多关节动力学连接。这也是mujoco的主要用途。可以快速开发多个物体的连接,并且对其物理特性进行仿真。具体使用什么语言去开发,其实并不重要,看大家的习惯吧。在本系列的文章中,我们从实战入手,使用python进行开发,且假设各位都已经有一点点python的开发基础了。
第0章 安装环境和显示一个mujoco模型
在本章的练习中,我们将使用到mujoco的传统例子——机械手臂。
首先,我们准备一下开发环境,使用pip install mujoco安装mujoco的python支持(这里最好是python3.10以上的版本,本人使用的是python3.11)。需要用到的xml文件(arm26.xml)和本节所用到的代码见附件。
我们先介绍一下几个基础概念:
模型
在mujoco中,模型是可以用于定义显示和操作的,可以使用xml存储。
视图
Viewer是mujoco最重要的组成部分,用于呈现出界面。一般来说,我们可以通过命令行调用:
python -m mujoco.viewer --mjcf=arm26.xml
执行该命令后,可以看到一个所谓2连接6肌肉的手臂,可以通过按钮来控制这个手臂
[localvideo]e1308ec00eb9ee7d1b90c454b7ab00e9[/localvideo]
用代码载入
#直接pip install mujoco安装
import mujoco.viewer
m = mujoco.MjModel.from_xml_path('arm26.xml')
v = mujoco.viewer.launch(m)
核心就两条,因为太过简单,就不怎么介绍了吧
m = mujoco.MjModel.from_xml_path('arm26.xml')
v = mujoco.viewer.launch(m)
本章节用到模型xml文件
-
回复了主题帖:
撒积分啦!!机器人开发圈公众号上线、还有多个新板块设立哦~~
恭喜恭喜
-
回复了主题帖:
四足机器人学习资料
freebsder 发表于 2025-2-20 19:21
arduino控制的?应该没那么智能吧
确实是arduino。。。
- 2025-02-20
-
上传了资料:
四足机器人
-
发表了主题帖:
四足机器人学习资料
上传两个我珍藏模型——以前一直以为有时间能弄出来玩玩的,一拖就是几年
[localvideo]187a7cfaf2d55df5399c29f4a5496992[/localvideo]
-
回复了主题帖:
【过年都玩啥】话说探友们过年都玩啥了呢?
回乡炸牛屎。。。
- 2025-02-17
-
回复了主题帖:
你参加哪吒2的百亿项目了吗?
smartzheng981 发表于 2025-2-17 08:55
父亲是大军区最高将领,母亲娘家背景深厚,大哥是老大秘书,二哥是老二秘书,这种人又能差到哪去
还有师傅太乙,十二常委之一……
-
回复了主题帖:
关于一个成绩分类的C语言实现的两种方式
python ,没有switch。。。总有它的道理
-
回复了主题帖:
【新年点灯】link2
okhxyyo 发表于 2025-2-11 14:25
太可爱了!!有那种玩古早游戏的赶脚
就是太古时代的游戏了,网上已经找不到原始的了,只有后面几代的,下面这张图已经是可以找到最早游戏的截图了,画质已经大有改善了
和女生一起进房间可以加血,不过对话总感觉有让人想歪(也许就是日本的特色。。。)