构建世界

img
img

在视图菜单下的 最后一项 显示灯光位置 这点和说明书不匹配

img
img

改变外观属性

img
img

添加一个放在地面上的物体,如果添加物理属性需要设置边界模型,否则就掉下去了。。。

img
img

按照例程添加墙

img
img

添加机器人,差动轮模型加上仅用于显示的外观

img
img

处理碰撞时其实是以一个box来处理,而不是按照曲面处理的

摆弄一个下午Webots的成果,整理一下。

编程控制

空的模板 void.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/*
* File:
* Date:
* Description:
* Author:
* Modifications:
*/
/*
* You may need to add include files like <webots/distance_sensor.h> or
* <webots/differential_wheels.h>, etc.
*/
#include <webots/robot.h>
/*
* You may want to add defines macro here.
*/
#define TIME_STEP 64
/*
* You should put some helper functions here
*/
/*
* This is the main program.
* The arguments of the main function can be specified by the
* "controllerArgs" field of the Robot node
*/
int main(int argc, char **argv)
{
/* necessary to initialize webots stuff */
wb_robot_init();
/*
* You should declare here DeviceTag variables for storing
* robot devices like this:
* WbDeviceTag my_sensor = wb_robot_get_device("my_sensor");
* WbDeviceTag my_actuator = wb_robot_get_device("my_actuator");
*/
/* main loop */
do {
/*
* Read the sensors :
* Enter here functions to read sensor data, like:
* double val = wb_distance_sensor_get_value(my_sensor);
*/
/* Process sensor data here */
/*
* Enter here functions to send actuator commands, like:
* wb_differential_wheels_set_speed(100.0,100.0);
*/
/*
* Perform a simulation step of 64 milliseconds
* and leave the loop when the simulation is over
*/
} while (wb_robot_step(TIME_STEP) != -1);
/* Enter here exit cleanup code */
/* Necessary to cleanup webots stuff */
wb_robot_cleanup();
return 0;
}

直接修改例程 hexapod.c

hexapod例程源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/*
* File: hexapod.c
* Date: September 22th, 2005
* Description: Alternate tripod gait using linear servos
* Author: Yvan Bourquin
* Modifications:Simon Blanchoud - September 12th, 2006
* Indentation of the code so that it follows the Webots Coding
* Standards
*
* Copyright (c) 2006 Cyberbotics - www.cyberbotics.com
*/
#include <webots/robot.h>
#include <webots/servo.h>
#include <stdio.h>
#define TIME_STEP 16
#define NUM_SERVOS 12
#define NUM_STATES 6
#define FRONT +0.7
#define BACK -0.7
#define HI +0.02
#define LO -0.02
int main() {
const char *SERVO_NAMES[NUM_SERVOS] = {
"hip_servo_r0",
"hip_servo_r1",
"hip_servo_r2",
"hip_servo_l0",
"hip_servo_l1",
"hip_servo_l2",
"knee_servo_r0",
"knee_servo_r1",
"knee_servo_r2",
"knee_servo_l0",
"knee_servo_l1",
"knee_servo_l2"};
WbDeviceTag servos[NUM_SERVOS];
const double pos[NUM_STATES][NUM_SERVOS] = {
{BACK, FRONT, BACK, -FRONT, -BACK, -FRONT, LO, HI, LO, HI, LO, HI},
{BACK, FRONT, BACK, -FRONT, -BACK, -FRONT, HI, HI, HI, HI, HI, HI},
{BACK, FRONT, BACK, -FRONT, -BACK, -FRONT, HI, LO, HI, LO, HI, LO},
{FRONT, BACK, FRONT, -BACK, -FRONT, -BACK, HI, LO, HI, LO, HI, LO},
{FRONT, BACK, FRONT, -BACK, -FRONT, -BACK, HI, HI, HI, HI, HI, HI},
{FRONT, BACK, FRONT, -BACK, -FRONT, -BACK, LO, HI, LO, HI, LO, HI}
};
int elapsed = 0;
int state, i;
wb_robot_init();
for (i = 0; i < NUM_SERVOS; i++) {
servos[i] = wb_robot_get_device(SERVO_NAMES[i]);
if (!servos[i]) {
printf("could not find servo: %s\n",SERVO_NAMES[i]);
}
}
while(wb_robot_step(TIME_STEP)!=-1) {
elapsed++;
state = (elapsed / 25 + 1) % NUM_STATES;
for (i = 0; i < NUM_SERVOS; i++) {
wb_servo_set_position(servos[i], pos[state][i]);
}
}
wb_robot_cleanup();
return 0;
}
img
img

修改电机旋转方向

img
img

去掉步态数组的负号 原地转

img
img

受设定的舵机范围限制,只能转到极限角度

img
img

控制周期内来不及调整的话,就会一直打转

img
img

改成电机的 原地打转 不需要伸缩足了

先在例子上直接修改,了解一下后续流程。将hexapod例程中的舵机的旋转方向修改一下,就可以行走了!

注意没有伸缩腿是走不动的,前后力量抵消,原地运动。

对步态数组进行简单修改试试,去掉里面的负号,得到原地打转的效果。

下面把舵机换成电机,需要取消对打角最大最小值的限定。

查阅了一下手册,

When both minPosition and maxPosition are zero (the default), the soft limits are deactivated

都设置为0的时候就没有限制了!好了,下面可以试试电机的效果了,注意转角的范围是负无穷到正无穷。控制的话就是每次增加一定的转角值就行了。注意还要调整一下控制周期,如果在控制周期内来不及调整的话,就会一直打转(都以最大力量向前摆动)。

servo作为电机使用的旋转写法:

1
2
3
4
5
6
7
8
9
10
const char *SERVO_NAME = "servo";
WbDeviceTag servo;
servo = wb_robot_get_device(SERVO_NAME);
if (!servo) {
printf("could not find servo: %s\n",servo);
}
wb_servo_set_position(servo, INFINITY);
wb_servo_set_velocity(servo, 6.28); // 1 rotation per second

接触面

img
img

狗与地面接触的部分使用圆球模拟的

img
img

一个接触面

关于构造自定义边界物体的问题

边界物体是仿真的重点,外观做多么华丽都对物理仿真没什么区别,只是看着不同罢了。

不是所有的形状都可以作为边界物体的:

采用USE使用一个形状时,出现问题:

DEF LEG Robot (name=’solid’): boundingObject: ignoring illegal Extrusion node in the geometry field of a Shape node

Failed to create geometry for a Extrusion object

测试了一下默认的Extrusion形状能否构建边界物体,结果失败了, 还是上面的提示,于是找官网说明,在官网说明第七节中,介绍了如何选择边界对象的问题,引用原文如下:

7.6.5 How to choose bounding Objects?

As said before, minimizing the number of bounding objects increases the simulation speed. However choosing the bounding objects primitives carefully is also crucial to increase the simulation speed.

Using a combination of Sphere, Box, Capsule and Cylinder nodes for defining objects is very efficient. Generally speaking, the efficiency of these primitives can be sorted like this: Sphere > Box > Capsule > Cylinder. Where the Sphere is the most efficient. But this can be neglected for a common usage.

The IndexdedFaceSet geometry primitive can also be used in a bounding object. But this primitive is less efficientthan the other primitives listed above. Moreover its behavior is sometimes buggy. For this reasons, we don’t recommend using the IndexdedFaceSet when another solution using a combination of the other primitives is possible.

Grounds can be defined using the Plane or the ElevationGrid primitives. The Plane node is much more efficient than the ElevationGrid node, but it can only be used to model a flat terrain while the ElevationGrid can be used to model an uneven terrain.

因此选择球形最利于仿真,从软件自带手册的关于形状的一节可以看出,对于特殊的形状,要么用支持的简单形状组合,要么可以用 IndexdedFaceSet 绘制。

而IndexdedFaceSet 的绘制是非常麻烦的,大概需要通过每一个构成面的各个顶点以及顶点索引序列声明各个构成面,还要通过构成边索引和边的二维坐标值声明构成边,简直要吐血。而且还有问题:

More than 3 vertices defined for a face in IndexedFaceSet, can’t create boundingObject

一张面必须是3个点构成的,否则不能构造碰撞物体。

再加上前面说明的低效率less efficient 和可能出错sometimes buggy,还是选择组合的方式吧。

机器人构建

img
img
img
img

robot结构树

img
img

让我们从前面的机器人身上碾压过去 哈哈

img
img

步态慢动作

先创建一个身体,solid完成可以转换为robot(闪电工具)

添加上电机,场景结构树设计可参考狗机器人的结构树。

创建好了后输出(场景树上方按钮),就可以带上机器人到各种世界逛逛了。。。