9、教程-7 Supervisor

主管监督一个世界,并可以设置或获取有关它的信息。本教程将教你:

  • 使用supervisor来移动物体;
  • 怎样删除节点以及在原地生成另外一个节点;
  • 如何跟踪场景中对象的演变;
  • 如何更改对象的属性,即其颜色。

这些只是监理能够完成的一些任务,请参阅其文件以获得完整的概述。但是,请注意,即使启用了监控器选项,也不可能直接访问安装在不同机器人上的设备记录的测量结果。

 设置环境并添加一个Supervisor

1、新建一个工程命名为my_supervisor;

2、同时将世界文件的名字命名为my_supervisor.wbt;

3、将所有的选项打钩,包括"Add a rectangle arena";

4、为了有更大的空间,更改floorSize域设置为10*10;

5、添加一个BB-8机器人到场景;通过+按钮,PROTO nodes (Webots projects) / robots / sphero / bb8.

6、为了教程的目的,移除BB-8的默认控制器通过点击controller域,将Select选为none;

7、添加一个简单的机器人节点到场景,这将称为我们的Supervisor。通过点击ADD按钮,在base nodes类中可以找到Robot节点。为了更好的跟踪它,将它的名字域更改为supervisor。

8、尽管名称发生了更改,但该节点目前仍然只是一个机器人,要将该机器人转变为supervisor,需要将其主管字段设置为“TRUE”;

9、跟普通的机器人一样,一个supervisor的行为由一个控制器来定义。添加一个控制器,选择适合的语言。

10、扩展Robot节点,按下controller域,点击Select按钮为了给你创建的控制器赋予supervisor的属性。

11、保存。

使用Supervisor来移动物体

本节将编程supervisor来移动BB-8机器人到不同的位置。需要注意的是,为了实现这一点,我们实际上是在作弊,而不是指示BB-8移动到一个新的位置,我们将把它运送到那里。换言之,这场运动将忽略所有的物理因素,但这就是监管者的力量所在,因为它可以随心所欲地改变规则。

为了获得supervisor的权力,因此需要对控制器进行一些细微的更改。首先,根据您选择并保存的语言,用以下代码替换默认控制器的内容。
这些变化包括:

  • 导入Supervisor库/模块,而不是Robot库/模块
  • 与其创建Robot实例,不如创建Supervisor实例。

重要的是要记住,supervisor只不过是一个拥有特殊力量的机器人,这意味着无论机器人能做什么,supervisor也能。这意味着,如果您有一个supervisor实例,则不需要Robot实例。例如,决定控制器速度的无限循环(即:while robot.step(TIME_step)!=-1) 不需要更改,因为supervisor也可以更改。

以下是根据您选择的编程语言所需遵循的说明:

将控制器的内容替换为以下内容。使用“build”按钮保存并编译它。

#include <webots/robot.h>
#include <webots/supervisor.h>
#include <stdio.h>

#define TIME_STEP 32

int main(int argc, char **argv) {
  wb_robot_init();

  // [CODE PLACEHOLDER 1]

  int i = 0;
  while (wb_robot_step(TIME_STEP) != -1) {
    // [CODE PLACEHOLDER 2]

    i++;
  }

  wb_robot_cleanup();

  return 0;
}

将BB-8移动到一个新位置非常简单,如果您希望在没有supervisor帮助的情况下这样做,您只需将其位移字段更改为所需值,例如0 0 2.5。supervisor做这件事的方式基本相同

使用Supervisor移动BB-8。原则上,世界可能非常复杂,因此有必要找到一种方法,在其他物体中唯一识别我们的BB-8。为此,我们可以使用教程2中探讨的DEF机制。单击场景树中的BB-8节点,并为其指定DEF名称“BB-8”,然后保存世界。
在后台,每个节点都可以通过一个节点引用进行唯一标识,通过拥有该引用,我们可以对其进行修改。要检索引用,可以使用supervisor函数wb_supervisor_node_get_from_def。在CODE PLACEHOLDER 1中,检索BB-8的节点引用。

WbNodeRef bb8_node = wb_supervisor_node_get_from_def("BB-8");

现在我们可以访问该节点,我们需要访问它的平移字段,特别是我们需要对该字段的引用,就像我们刚刚对该节点所做的那样。为此,可以使用wb_supervisor_node_get_field函数。

WbFieldRef translation_field = wb_supervisor_node_get_field(bb8_node, "translation");

最后,现在有了对平移字段的引用,剩下要做的就是将其设置为不同的值。同样,supervisorAPI有所有必要的工具来完成这项工作。平移字段是SFVec3类型,这意味着它是一个三维向量。可以使用wb_supervisor_field_set_sf_vec3f函数设置此字段的值。

if (i == 0) {
  const double new_value[3] = {2.5, 0, 0};
  wb_supervisor_field_set_sf_vec3f(translation_field, new_value);
}

这就是它的全部。如果你保存、构建和运行模拟,你会看到BB-8立即被运送到一个新的位置。

这是一个简单的例子,但无论您希望更改哪个领域,原则都保持不变。例如,您可以增加对象的大小,也许可以更改其颜色,更改灯光条件,或者在超出范围时重置其位置,选项是无限的。这只是一个获取节点引用的问题,可以通过名称从中获取字段引用,并通过使用适合您尝试更改的类型的函数来设置其值。

生成和移动节点

supervisor也可以用于填充环境,从而允许动态设置场景。本节重点介绍如何添加和删除节点,特别是我们将从这个世界中删除BB-8,并用另一个机器人Nao替换它。

正在删除和添加节点。在上一节中,我们已经了解了如何检索对象的节点引用。可以使用wb_supervisor_node_remove函数从场景树中移除节点。如果条件不是必要的,它只需在移除前增加10步延迟,使其更加明显。在CODE PLACEHOLDER 2中添加以下代码。

if (i == 10)
  wb_supervisor_node_remove(bb8_node);

经过10个时间步长后,BB-8将从场景中移除。现在,让我们在20个时间步长后添加Nao机器人。为了添加一个节点,我们必须知道我们希望在场景树中的何处生成它。是否应该将其添加到场景树的顶层?它应该作为另一个节点的字段插入吗?这些问题将改变节点将如何插入以及需要使用哪个主管功能,但其中不变的因素是我们需要参考这个位置。在这种情况下,Nao机器人将被添加到场景树中的最后一个位置,BB-8曾经出现在那里。首先,我们需要宣布Nao-to-Webots是我们创建的世界的重要PROTO。要继续,请单击位于场景树顶部的IMPORTABLE EXTERNPROTO按钮。位于场景树下方的字段编辑器应显示一个IMPORTABLE EXTERNPROTO窗格,其中包含一个名为“Insert new”的按钮。单击此按钮并从PROTO节点(Webots项目)部分选择Nao机器人。按下“插入”按钮。如果您将鼠标悬停在“插入新内容”按钮下方的Nao项目上,您将在工具提示中看到下载该项目的URL。保存世界文件,以便存储这些信息。
虽然不明显,但场景树实际上是一个“组”节点,场景树中的每个对象(如WorldInfo、Viewpoint、TexturedBackground等)只不过是定义为其子节点的节点。我们将这个包含所有内容的Group节点称为根节点。为了插入Nao机器人,我们需要的引用实际上是对根节点的子字段的引用。在CODE PLACEHOLDER 1标记的位置,以下代码允许获得此引用。

WbNodeRef root_node = wb_supervisor_node_get_root();
WbFieldRef children_field = wb_supervisor_node_get_field(root_node, "children");

要生成节点,您应该使用supervisor函数wb_supervisor_field_import_[mf/sf]_node_from_string。这些函数名称中的“mf_node”和“sf_node”组件指定插入对象的节点的类型。“mf_node”代表多字段节点,而“sf_node”则代表单字段节点。
如前所述,Nao应该添加到根节点的子字段中,正如您可能猜到的,这个子字段的类型是multi-field。
让我们在20个时间步长后从字符串中添加它,在CODE PLACEHOLDER 2中添加以下片段:

if (i == 20)
  wb_supervisor_field_import_mf_node_from_string(children_field, -1, "Nao { }");

“-1”指定我们希望在哪个位置插入节点,在这种情况下,将其插入最后一个位置。“Nao{}”是一个字符串,用于描述我们希望生成的内容。对象的描述方式是使用VRML97格式,这也是世界文件中使用的格式。20次后,Nao机器人将在场景中间生成。
假设我们希望Nao在BB-8曾经的位置上诞生,我们当然可以按照动手2的程序将其移动到那里,但这并不明智。事实上,我们可以直接在字符串中指定翻译字段!将字符串“Nao{}”替换为“Nao{translation 2.5 0 0.334}”,它将恰好在该位置生成。它并没有就此止步,我们可以用同样的方式定义它的控制器参数,或cameraWidth或它的任何其他参数。

技巧:如果您不熟悉VRML97,那么定义这些字符串的一个简单技巧就是让Webot为您完成。您可以手动创建对象(使用Webots界面),然后保存世界。保存时,Webots会将您构建的内容翻译成一系列文本。如果使用文本编辑器打开世界文件,则可以简单地复制对象的描述。

使用supervisor来跟踪位置

由于supervisor拥有无限的权力,它是跟踪模拟发展的完美工具。在本节中,我们将使用获得的知识来生成球,并在球落下时跟踪球的位置,以及当球接触地面时改变球的颜色。

我们需要使用wb_supervisor_field_import_mf_node_from_string函数在位置0 1 1处生成球,由于我们正在生成球,因此让我们获得对该节点和球的颜色字段的引用。但首先,我们必须将Ball宣布为可导入的的EXTERNPROTO,就像我们之前为Nao机器人所做的那样。完成后,在 CODE PLACEHOLDER 1中添加:

wb_supervisor_field_import_mf_node_from_string(children_field, -1, "DEF BALL Ball { translation 0 1 1 }");
WbNodeRef ball_node = wb_supervisor_node_get_from_def("BALL");
WbFieldRef color_field = wb_supervisor_node_get_field(ball_node, "color");

如果运行模拟,球应该出现并开始下落,直到与地面发生碰撞。
为了跟踪球的位置,我们可以获得对其平移字段的引用,并连续读取该值。然而,更简单的方法是使用为该任务创建的另一个监督函数,即wb_supervisor_node_get_position。在CODE PLACEHOLDER 2中添加:

const double *position = wb_supervisor_node_get_position(ball_node);
printf("Ball position: %f %f %f\n", position[0], position[1], position[2]);

既然我们可以跟踪它,让我们在它碰撞时立即更改球的颜色。由于球的半径为0.2,因此当位置的“Y”坐标小于该值时,我们可以更改颜色场。

if (position[2] < 0.2) {
  const double red_color[3] = {1, 0, 0};
  wb_supervisor_field_set_sf_color(color_field, red_color);
}

完整代码

#include <webots/robot.h>
#include <webots/supervisor.h>
#include <stdio.h>

#define TIME_STEP 32

int main(int argc, char **argv) {
  wb_robot_init();

  // [CODE PLACEHOLDER 1]
  WbNodeRef bb8_node = wb_supervisor_node_get_from_def("BB-8");
  WbFieldRef translation_field = wb_supervisor_node_get_field(bb8_node, "translation");

  WbNodeRef root_node = wb_supervisor_node_get_root();
  WbFieldRef children_field = wb_supervisor_node_get_field(root_node, "children");

  wb_supervisor_field_import_mf_node_from_string(children_field, -1, "DEF BALL Ball { translation 0 1 1 }");
  WbNodeRef ball_node = wb_supervisor_node_get_from_def("BALL");
  WbFieldRef color_field = wb_supervisor_node_get_field(ball_node, "color");

  int i = 0;
  while (wb_robot_step(TIME_STEP) != -1) {
    // [CODE PLACEHOLDER 2]
    if (i == 0) {
      const double new_value[3] = {2.5, 0, 0};
      wb_supervisor_field_set_sf_vec3f(translation_field, new_value);
    }

    if (i == 10)
      wb_supervisor_node_remove(bb8_node);

    if (i == 20)
      wb_supervisor_field_import_mf_node_from_string(children_field, -1, "Nao { translation 2.5 0 0.334 }");

    const double *position = wb_supervisor_node_get_position(ball_node);
    printf("Ball position: %f %f %f\n", position[0], position[1], position[2]);

    if (position[2] < 0.2) {
      const double red_color[3] = {1, 0, 0};
      wb_supervisor_field_set_sf_color(color_field, red_color);
    }

    i++;
  }

  wb_robot_cleanup();

  return 0;
}

 

posted on 2023-07-27 22:31  gary_123  阅读(79)  评论(0编辑  收藏  举报

导航