Webots控制器编程
本文主要内容是如何编写Webots控制器,使用语言为Python。
文章目录
- 1. 新增控制器
- 2. Hello World Example
- 3. 读取传感器
- 4. 使用执行器
- 5. 理解step和robot.step函数
- 6. 同时使用传感器和执行器
- 7. 控制器参数
1. 新增控制器
对机器人Robot新增控制器的方式:
Wizards -> New Robot Controller
默认的Python代码模版是:
# You may need to import some classes of the controller module. Ex:
# from controller import Robot, Motor, DistanceSensor
# 1. 导入相关控制器类
from controller import Robot# create the Robot instance.
# 2. 实例化控制器类得到控制的对象
robot = Robot()# get the time step of the current world.
# 3. 获取环境仿真时间步
timestep = int(robot.getBasicTimeStep())# You should insert a getDevice-like function in order to get the
# instance of a device of the robot. Something like:
# 4. 获取要操控的设备并设置仿真时间步
# motor = robot.getDevice('motorname')
# ds = robot.getDevice('dsname')
# ds.enable(timestep)# Main loop:
# - perform simulation steps until Webots is stopping the controller
# 5. 主循环中按照时间步进行仿真
while robot.step(timestep) != -1:# Read the sensors:# Enter here functions to read sensor data, like:# val = ds.getValue()# Process sensor data here.# Enter here functions to send actuator commands, like:# motor.setPosition(10.0)pass# Enter here exit cleanup code.
可以看到一般控制器程序的代码可以分为五部分:
- 导入相关控制器类
- 实例化控制器类得到控制的对象
- 获取环境仿真时间步
- 获取要操控的设备并设置仿真时间步
- 主循环中按照时间步进行仿真
2. Hello World Example
from controller import Robotrobot = Robot()while robot.step(32) != -1:print("Hello World!")
在主循环中每隔32ms会进行执行一次,执行的内容可能需要1ms也可能需要1min的时间完成这次仿真的推进,具体的时间需要看执行内容的复杂程度。
3. 读取传感器
from controller import Robot, DistanceSensorTIME_STEP = 32robot = Robot()# my_distance_sensor这个需要根据你命名的传感器名称进行定义
sensor = robot.getDevice("my_distance_sensor")
# 传感器需要先启用才能使用,TIME_STEP传感器的两次数据更新的时间间隔
# 一般设置TIME_STEP和仿真时间步相同
sensor.enable(TIME_STEP)while robot.step(TIME_STEP) != -1:value = sensor.getValue()print("Sensor value is: ", value)
需要注意的是有些传感器返回的值不是标量而是向量,如下代码所示:
GPS.getValues()
Accelerometer.getValues()
Gyro.getValues()# return the sensor measurement as an array of 3 floating point numbers: `[x, y, z]`.
values = gps.getValues()# OK, to read the values they should never be explicitly deleted by the controller code
print("MY_ROBOT is at position: %g %g %g" % (values[0], values[1], values[2]))# there is no need to copy these values
4. 使用执行器
下面的示例显示了如何使用 2 Hz 正弦信号使旋转电机振荡。
from controller import Robot, Motor
from math import pi, sinTIME_STEP = 32robot = Robot()
# 获取机器人上名为"my_motor"的电机设备
motor = robot.getDevice("my_motor")# 设置频率F为2 Hz,用于控制电机的周期性运动,使电机每秒进行两个完整周期的运动。
F = 2.0 # frequency 2 Hz
t = 0.0 # elapsed simulation timewhile robot.step(TIME_STEP) != -1:position = sin(t * 2.0 * pi * F)motor.setPosition(position)t += TIME_STEP / 1000.0
与传感器不同,执行器不需要明确启用。为了控制运动,通常有用的是将运动分解为与控制步骤相对应的离散步骤。和以前一样,这里使用无限循环:在每次迭代时,根据正弦方程计算新的目标位置。
需要注意的是,motor.setPosition
函数存储新位置,但它不会立即启动电机。有效驱动调用 robot.step
函数开始。
当 robot.step
函数返回时,电机已移动一定的(线性或旋转)量,该量取决于目标位置、控制步骤的持续时间(使用 robot.step
函数参数指定)、速度、加速度、力等电机“.wbt”描述中指定的参数。例如,如果指定非常小的控制步长或较低的电机速度,则当 robot.step
函数返回时,电机不会移动太多。在这种情况下,旋转电机需要几个控制步骤才能到达目标位置。如果指定更长的持续时间或更高的速度,则当 robot.step
函数返回时,电机可能已完全完成运动。
请注意,motor.setPosition
函数仅指定所需的目标位置。就像真实的机器人一样,旋转电机有可能无法到达该位置(仅在基于物理的模拟中),因为它被障碍物阻挡或因为电机的扭矩(最大力)不足以抵抗重力等。
如果要同时控制多个旋转电机的运动,则需要使用motor.setPosition
函数分别为每个旋转电机指定所需的位置。然后您需要调用一次 robot.step
函数来同时驱动所有旋转电机。
5. 理解step和robot.step函数
Webots 使用两种不同的时间步长:
- The simulation step(在场景树中指定:
WorldInfo.basicTimeStep
) - The control step(指定为每个机器人的
robot.step
函数的参数)
The simulation step(模拟步长)是 WorldInfo.basicTimeStep
中指定的值(以毫秒为单位)。它表示一步模拟的持续时间,即两次计算每个模拟对象的位置、速度、碰撞等的时间间隔。如果模拟使用physics
(vs. kinematics),则模拟步骤还指定需要应用于模拟刚体的力和扭矩的两次计算之间的间隔。
The control step(控制步长)是控制循环迭代的持续时间。它与传递给 robot.step
函数的参数相对应。robot.step
函数将指定持续时间的控制器时间提前。同时,它还会根据控制器时间将传感器和执行器数据与模拟器同步。
每个控制器都需要定期调用 robot.step
函数。如果控制器不调用 robot.step
函数,则传感器和执行器将不会更新,并且模拟器将阻塞(仅在同步模式下)。因为需要定期调用,所以 robot.step
函数调用通常放在控制器的主循环中。
a simulation step的执行是一个原子操作:它不能被中断。因此,传感器测量或电机驱动只能在两个simulation step之间进行。因此,每个 robot.step
函数调用指定的The control step
必须是simulation step
的倍数。因此,例如,如果simulation step
为 16 ms,则传递给 robot.step
函数的控制步参数可以是 16、32、64、128 等。
如果模拟以逐步模式运行,即通过单击Step
按钮,则执行具有模拟步骤持续时间的单个步骤。下图详细描述了仿真状态、控制器状态和Step
点击之间的同步。
6. 同时使用传感器和执行器
Webots
和每个机器人控制器在不同的进程中执行。例如,如果模拟涉及两个机器人,则总共会有三个进程:一个是 Webots
进程,两个是两个机器人进程。在调用 robot.step
函数时,每个机器人控制器进程都会与 Webots 进程交换传感器和执行器数据。例如,my_leg.setPosition
函数不会立即将数据发送给 Webots
。相反,它会在本地存储数据,并在调用 robot.step
函数时有效发送数据。
因此,下面的代码片段是一个糟糕的示例。显然,第一次调用 my_leg.setPosition
函数时指定的值将被第二次调用覆盖:
my_leg.setPosition(0.34) # BAD: ignored
my_leg.setPosition(0.56)
robot.step(40) # BAD: we don't test the return value of this function
同样,这段代码也没有什么意义:
while robot.step(40) != -1:d1 = sensor.getValue()d2 = sensor.getValue()if d2 > d1: # WRONG: d2 will always equal d1 hereavoidCollision()
由于在两次传感器读数之间没有调用 robot.step
函数,因此传感器返回的值不可能在此期间发生变化。一个正确的版本如下:
while robot.step(40) != -1:d1 = sensor.getValue()if robot.step(40) == -1:breakd2 = sensor.getValue()if d2 > d1:avoidCollision()
然而,通常推荐的方法是在主控制循环中调用一个 robot.step
函数,并使用它同时更新所有传感器和执行器,如下所示:
while robot.step(40) != -1:readSensors()actuateMotors()
请注意,在循环开始时调用 robot.step
函数非常重要,以确保传感器在进入 readSensors
函数之前已经具有有效值。
这是一起使用传感器和执行器的完整示例。这里使用的机器人使用差速转向。它使用两个距离传感器(DistanceSensor
)来检测障碍物。
from controller import Robot, Motor, DistanceSensorTIME_STEP = 32robot = Robot()left_sensor = robot.getDevice("left_sensor")
right_sensor = robot.getDevice("right_sensor")
left_sensor.enable(TIME_STEP)
right_sensor.enable(TIME_STEP)left_motor = robot.getDevice("left_motor")
right_motor = robot.getDevice("right_motor")
left_motor.setPosition(float('inf'))
right_motor.setPosition(float('inf'))
left_motor.setVelocity(0.0)
right_motor.setVelocity(0.0)while robot.step(TIME_STEP) != -1:# read sensorsleft_dist = left_sensor.getValue()right_dist = right_sensor.getValue()# compute behavior (user functions)left = compute_left_speed(left_dist, right_dist)right = compute_right_speed(left_dist, right_dist)# actuate wheel motorsleft_motor.setVelocity(left)right_motor.setVelocity(right)
在Webots仿真环境中,控制电机的方式主要有两种:位置控制和速度控制。而在这段代码中,通过将电机的位置设置为“无限”float('inf')
,就可以使电机进入速度控制模式 。
- 位置控制模式:通常情况下,如果给电机设置一个固定的目标位置(例如一个角度或距离),电机会尝试旋转到该位置并停在那里,这就是“位置控制”。
- 速度控制模式:通过将电机位置设为“无限”
float('inf')
,Webots将认为电机的目标位置是无限远的,这种情况下,电机会进入“速度控制模式”,即不再关注目标位置,而是只根据设定的速度值进行旋转或移动。
7. 控制器参数
在.wbt
文件中,可以指定控制器启动时传递的参数。这些参数在机器人节点的 controllerArgs
字段中指定,并作为主函数的参数传递。例如,这可用于指定每个机器人控制器的不同参数。请注意,使用 MATLAB 时不支持控制器参数检索。
比如:
Robot {...controllerArgs "one two three"...
}
如果控制器的名称是 “demo”,那么就会出现这段示例控制器代码
from controller import Robot
import sysrobot = Robot()for i in range(0, len(sys.argv)):print("argv[%i]=%s" % (i, sys.argv[i]))
argv[0]=demo
argv[1]=one
argv[2]=two
argv[3]=three
相关文章:

Webots控制器编程
本文主要内容是如何编写Webots控制器,使用语言为Python。 文章目录 1. 新增控制器2. Hello World Example3. 读取传感器4. 使用执行器5. 理解step和robot.step函数6. 同时使用传感器和执行器7. 控制器参数 1. 新增控制器 对机器人Robot新增控制器的方式࿱…...

舷外机,高效动力的选择,可靠性能的保障_鼎跃安全
舷外机是现代船只动力系统中的核心设备,广泛应用于娱乐船、渔船、巡逻船、救援船等多种场景。它不仅提供船只的动力支持,还因其结构简便、操作灵活和维护方便,成为水上作业的重要组成部分。 一、舷外机的功能作用 1. 强劲动力源 舷外机是船…...

计算机新手练级攻略——如何搜索问题
目录 计算机学生新手练级攻略——如何搜索问题1.明确搜索意图2.使用精确关键词3.使用专业引擎搜索4.利用好技术社区1. Stack Overflow2. GitHub3. IEEE Xplore4. DBLP 5.使用代码搜索工具1. GitHub 代码搜索2. Stack Overflow 代码搜索3. Papers with Code4. IEEE Xplore 6.查阅…...

echarts-gl 3D柱状图配置
1. 源码 此demo可以直接在echarts的编辑器中运行 option {title: {text: 产量图,textStyle: {color: rgba(255, 255, 255, 1),fontSize: 17},left: center},tooltip: {},legend: {show: false,orient: vertical,x: left,top: 0,right: 20,textStyle: {fontSize: 12}},visualM…...

设计模式之模版方法模式(Template)
一、模版方法模式介绍 1、模版方法模式定义: 模板方法模式(template method pattern)原始定义是:在操作中定义算法的框架,将一些 步骤推迟到子类中。模板方法让子类在不改变算法结构的情况下重新定义算法的某些步骤。 模板方法中的算法可以理…...

背包九讲——背包问题求具体方案
目录 背包问题求具体方案 1. 01 背包问题 题目:12. 背包问题求具体方案 - AcWing题库 算法思路: 代码实现: 2. 多重背包问题 算法思路: 3. 完全背包问题 算法思路: 代码实现: 背包问题第九讲—…...

Python http打印(http打印body)flask demo(http调试demo、http demo、http printer)
文章目录 代码解释 代码 # flask_http_printer.pyfrom flask import Flask, request, jsonify import jsonapp Flask(__name__)app.route(/printinfo, methods[POST]) def print_info():# 分隔符separator "-" * 60# 获取请求头headers request.headers# 获取 JS…...
JSF HTML标签教程一口气讲完!(下)
JSF OutputScript示例 JSF教程 - JSF OutputScript示例 h:outputScript标记渲染类型为“script"的HTML元素,类型为“text/javascript"。 此标记将外部JavaScript文件添加到JSF页面。 以下JSF标记 <h:outputScript library"js" name"…...
cmake报错The link interface of target “gRPC::grpc“ contains: OpenSSL::SSL 解决
系统环境:麒麟V10 报错描述: The link interface of target "gRPC::grpc" contains: OpenSSL::SSL but the target was not found. Possible reasons include: * There is a typo in the target name. * A find_package call is missing fo…...

C语言PythonBash:空白(空格、水平制表符、换行符)与转义字符
C语言 空白 C语言中的空白(空格、水平制表符、换行符)被用于分隔Token,因此Token间可以有任意多个空白。 // 例1 printf("Hello, World!"); 例1中存在5个Token,分别是: printf("Hello, World! \n&qu…...
【Python】轻松解析JSON与XML:Python标准库的json与xml模块
轻松解析JSON与XML:Python标准库的json与xml模块 在现代数据处理与交换中,JSON(JavaScript Object Notation)和XML(eXtensible Markup Language)是最常用的两种数据格式。它们广泛应用于API数据传输、配置…...

物联网对商业领域的影响
互联网彻底改变了通信方式,并跨越了因地理障碍造成的人与人之间的鸿沟。然而,物联网(IoT)的引入通过使设备能够连接到互联网,改变了设备的功能。想象一下,你的闹钟连接到互联网,并且能够用你的声…...

第16章 SELECT 底层执行原理
一、SELECT查询的完整结构 1.1 方式一(SQL 92语法) SELECT ..., ..., ... FROM ..., ..., ... WHERE 多表的连接条件 AND 不包含组函数的过滤条件 GROUP BY ..., ... HAVING 包含组函数的过滤条件 ORDER BY ... ASC/DESC LIMIT ..., ... 1.2 方式二&a…...
python查询日志,并组装sql,修复缺失的数据
前言 由于mysql链接超时波动,导致数据缺失,需要根据日志填补数据 流程 获取确实数据的订单列表 搜索日志,获取请求日志 根据请求日志拼装sql 打印sql供修复数据 代码 因为我们日志打印的有问题,所以这里用字符串截取获取入…...

RecyclerView进阶知识讲解
在 Android 开发中,RecyclerView 是一种高效的列表和网格布局控件,用于显示大规模数据。尽管基本使用方法简单,但深入理解并掌握其高级进阶用法能大幅提升用户体验和应用性能。下面,我将从布局管理、动画和手势、自定义缓存、优化…...

C语言 函数
时间:2024.11.10-11.11 一、学习内容 1、什么是函数 函数:程序中独立的功能。将反复书写的代码,又不确定什么时候回用到的代码打包起来。 2、函数的基本格式 函数的定义格式(写在main函数外) void 函数名() { 函数…...

windows中docker安装redis和redisinsight记录
创建一个Redis运行容器,命令如下 docker run -it -d --name redis -p 6379:6379 redis --bind 0.0.0.0 --protected-mode no -d 代表Redis容器后台运行 --name redis 给创建好的容器起名叫redis -p 6379:6379 将容器的6379端口映射到宿主机的6379端口,注…...

itextpdf打印A5的问题
使用A5打印的时候,再生成pdf是没有问题的。下面做了一个测试,在打印机中,使用A5的纸张横向放入,因为是家用打印机,A5与A4是同一个口,因此只能这么放。 使用itextpdf生成pdf,在浏览器中预览pdf是…...

qt QUndoView详解
1、概述 QUndoView 是 Qt 框架中用于显示 QUndoStack(撤销堆栈)内容的视图类。它通常与 QUndoStack 一起使用,为用户提供了一个可视化的界面来查看和操作撤销/重做历史。QUndoView 可以显示堆栈中的每个命令,并允许用户通过界面进…...
python+智谱AI-实现钉钉消息自动回复
python智谱AI-实现钉钉消息自动回复 实现了电脑窗口切换,截图识别未读消息,与语言模型交互后,将答案带入到钉钉窗口中。偷个懒,直接贴代码了,后续不断完善注释,如果遇到读不懂的地方,欢迎交流。…...

GC1808:高性能音频ADC的卓越之选
在音频处理领域,高质量的音频模数转换器(ADC)是实现精准音频数字化的关键。GC1808,一款96kHz、24bit立体声音频ADC,以其卓越的性能和高性价比脱颖而出,成为众多音频设备制造商的理想选择。 GC1808集成了64倍…...

AWSLambda之设置时区
目标 希望Lambda运行的时区是东八区。 解决 只需要设置lambda的环境变量TZ为东八区时区即可,即Asia/Shanghai。 参考 使用 Lambda 环境变量...

[C++错误经验]case语句跳过变量初始化
标题:[C错误经验]case语句跳过变量初始化 水墨不写bug 文章目录 一、错误信息复现二、错误分析三、解决方法 一、错误信息复现 write.cc:80:14: error: jump to case label80 | case 2:| ^ write.cc:76:20: note: crosses initialization…...

【字节拥抱开源】字节团队开源视频模型 ContentV: 有限算力下的视频生成模型高效训练
本项目提出了ContentV框架,通过三项关键创新高效加速基于DiT的视频生成模型训练: 极简架构设计,最大化复用预训练图像生成模型进行视频合成系统化的多阶段训练策略,利用流匹配技术提升效率经济高效的人类反馈强化学习框架&#x…...

【JavaEE】万字详解HTTP协议
HTTP是什么?-----互联网的“快递小哥” 想象我们正在网上购物:打开淘宝APP,搜索“蓝牙耳机”,点击商品图片,然后下单付款。这一系列操作背后,其实有一个看不见的“快递小哥”在帮我们传递信息,…...

如何使用CodeRider插件在IDEA中生成代码
一、环境搭建与插件安装 1.1 环境准备 名称要求说明操作系统Windows 11JetBrains IDEIntelliJ IDEA 2025.1.1.1 (Community Edition)硬件配置推荐16GB内存50GB磁盘空间 1.2 插件安装流程 步骤1:市场安装 打开IDEA,进入File → Settings → Plugins搜…...

OGG-01635 OGG-15149 centos服务器远程抽取AIX oracle11.2.0.4版本
背景描述 有一套ogg远程抽取的环境,源端是AIX7.1环境的oracle 11.2.0.4版本的数据库,中间是OGG抽取服务器,目标端是centos 7.9环境的oracle 19c。 采用集成模式远程抽取源端数据正常,但是经典模式远程抽取源数据的时候抽取进程启…...
C语言指针与数组sizeof运算深度解析:从笔试题到内存原理
前两天跟着数组指针的教程: // #self 视频里的笔试题 !!!vipint b12[3][4] {0};printf("%ld \n", sizeof(b12[0]));printf("%ld \n", sizeof(*b12));printf("%ld \n", sizeof(*(b12 1)));printf("%ld \n", sizeof(*(&am…...
四自由度机械臂Simulink仿真设计与实现
四自由度机械臂Simulink仿真设计与实现 摘要 本文详细介绍了基于MATLAB/Simulink的四自由度机械臂建模、仿真与控制实现。通过建立完整的运动学和动力学模型,设计PID控制器,实现轨迹跟踪功能,并利用3D可视化技术进行仿真验证。全文涵盖理论建模、Simulink实现和仿真分析三…...
Ubuntu下有关UDP网络通信的指令
1、查看防火墙状态: sudo ufw status # Ubuntu 2、 检查系统全局广播设置 # 查看是否忽略广播包(0表示接收,1表示忽略) sysctl net.ipv4.icmp_echo_ignore_broadcasts# 查看是否允许广播转发(1表示允许)…...