基于python的NAO机器人开发02:多线程实现边唱歌边跳舞

在NAO上播放音频

  在NAO机器人上播放音频文件常用的库为ALAudioPlayer,里面有2个可以播放音乐的函数:play()playFile()

play()

  该函数的C++函数头为:

1
void play(const int& taskId, const float& volume, const float& pan)

  该函数有3个参数,其中第一个为必须的,后面2个是可选的。第一个参数为任务ID,即文件名,通常由ALAudioPlayer库里面的loadFile("文件名")函数产生的。第二个为音频的音量,其值为0.0-1.0,第三个为Stereo panorama requested (-1.0 : left / 1.0 : right)d。

1
2
3
4
5
6
from naoqi import ALProxy

audio = ALProxy("ALAudioPlayer", '169.254.67.213', 9559)

fileId = audio.loadFile("文件名绝对路径")
audio.play(fileId)

  首先建立一个ALAudioPlayer库的实例,然后用loadFile()加载音频文件,最后使用play()函数进行播放。

playFile()

  该函数的C++函数头为:

1
void playFile(const std::string& fileName, const float& volume, const float& pan)

  该函数基本和play()类似,只是第一个参数为文件名,即不需要在用loadFile()函数来转换。

1
2
3
4
5
6
from naoqi import ALProxy

audio = ALProxy("ALAudioPlayer", '169.254.67.213', 9559)

songfile = "文件名绝对路径"
audio.playFile(songfile)

将音频文件传入到NAO中

  NAO机器人存储器中自带一些音频文件,同时也支持将本地音频文件上传至NAO中。NAO机器人本身相当于一个服务器,本地计算机相当于主机,只要输入正确的IP地址和端口号即可访问和文件操作。常用的方式为自带的Choregraph软件和其他文件传输软件。

Choregraph软件

  NAO机器人自带的Choregraph软件可以将本地文件上传到NAO机器人的存储内存中,其文件传输协议为FTP模式。
  首先将NAO机器人连接到Choregraph软件中,具体可以参考另一篇博客:基于python的NAO机器人开发01。然后在连接选项中,选择高级->文件传送,此时必须是连接真机,虚拟机器人没有此功能。

  然后输入用户名(nao)和密码(初始为nao)。
  在空白处右击,选择创建文件夹即可创建自己的文件夹,点击上传功能并选择相应的本地文件即可将文件上传至NAO机器人中,此时文件存放的路径为:/home/nao/...

  例如新建一个test的文件夹,并将test_wav.wav音频文件上传至NAO机器人中,可以使用下面的代码播放音频。

1
2
3
4
5
6
7
8
from naoqi import ALProxy

def playMusic():
audio = ALProxy("ALAudioPlayer", '169.254.67.213', 9559)
songfile = "/home/nao/test/test_wav.wav"
audio.playFile(songfile)

playMusic()

  注:NAO机器人中,只能识别wav格式的音频文件,不支持mp3等其他格式的。

WinSCP软件

  除了使用Choregraph软件可以传输文件外,还可以使用其他的文件传输软件,比如WinSCP。输入其对应的IP地址和端口号,即可访问其内部文件夹。
  打开WinSCP软件后,首先选择FTP文件传输模式,然后输入相应的NAO机器人IP地址,用户名和密码同Choregraph软件。输入正确后,即可进入到机器人的内部存储文件夹。

  在WinSCP中上传本地文件,直接选中文件拖拽到相应位置即可,右击选择属性也可以直接更改其文件夹或文件的访问权限。

将python文件传入NAO机器人中,并直接运行

  除了可以上传音频文件,其他任何文件都可以上传至NAO机器人中,而NAO机器人中自带python的解释器,所以可以将py文件上传到NAO中,并直接运行python文件。
  NAO机器人内部使用的是linux操作系统,使用PuTTY软件可以进入到该系统中。linux系统的命令也都适用于此,输入相应的命令即可直接运行python文件。

登陆NAO系统

  打开PuTTY软件后,选择SSH登陆方式,然后输入正确的IP地址和端口号即可登陆NAO系统,用户名和密码同之前。

NAO系统中常用的Linux命令

  1. cd ~ :返回根目录
  2. cd /.../...:进入某个文件夹,例:cd /home/nao/test/ (TAB键可以自动补全)
  3. cd .. :返回上一级文件夹
  4. pwd:查看当前所在目录
  5. ls: 查看当前文件夹的内容(ls:list)
  6. ls -l:查看当前文件夹的内容和详细信息
  7. rm file:删除名为file的文件(rm:remove)
  8. rmdir dir:删除名为dir的目录(dir:dictionary)
  9. chmod \*** file:修改文件权限
      文件权限共分为3种,r:读权限,用数字4表示;w:写权限,用数字2表示;x:执行权限,用数字1表示。一共有3类用户:文件所有者,同组用户和其他用户。每种用户用1个数字表示。
      比如将文件所有者的权限改为可读可写可执行:chmod 700 file。将所有用户都改为可读可写可执行:chmod 777 file
      7表示4+2+1,即3个权限之和,file为完整的文件路径名。
  10. ifconfig:显示以太网信息
  11. su:登陆超级用户,密码为root
  12. reboot:重启
  13. shutdown -h now:现在关机(需要root权限)

在NAO中执行运行python文件

  NAO支持多种编程,其内部带有python的解释器,使用python \*.py文件可以直接运行。
  例如在/home/nao/目录下新建一个test的文件夹,并将之前的python文本文件和音频文件放入该文件夹中。首先利用cd /home/nao/test/命令进入该文件夹,然后输入python test.py命令,就可以实现之前的功能。
  注:如果音频不能正确播放,可能需要权限设置,将文件权限改为可读可写可执行即可。NAO有2块网卡,即有线网卡和无线网卡。分别对应一个IP地址,其本身也有一个本地IP地址,即127.0.0.1。当运行NAO本地的python文件时,可以将IP地址设置为有线连接或无线连接的IP地址,也可以直接设置为本地IP地址。

NAO机器人跳舞

  NAO机器人全身有25个自由度,通过控制每个自由度的变化可以实现多种不同的运动动作。
  ALMotionProxy库中的angleInterpolation()函数可以控制每个关节的变化,其函数头为:

1
void angleInterpolation(const AL::ALValue& names, const AL::ALValue& angleLists, const AL::ALValue& timeLists, const bool& isAbsolute)

  函数的第一个参数为关节的名字,第二个参数为关节的角度(弧度制),第三个参数为关节变化的时间(s),第四个参数为是否为相对变化,即变化的角度是否跟随上一个变化。
  NAO中的每个关节的名称可以参考NAO的官方文档,通过给每个关节不同的角度值就可以实现不同的动作,所谓舞蹈就是一连串动作的结合。
  这里参考了别人的跳舞代码:
  Dance模板库dance.py

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
class DancePart(object):
""" DancePart for Nao dance includes lists of names, times, and keys for Python
simplified dances exported from Choreographe"""

def __init__(self, part_length, pause_length, names, times, keys):
super(DancePart, self).__init__()
self.part_length = part_length
self.pause_length = pause_length
self.names = names
self.times = times
self.keys = keys

def get_part_length(self):
return self.part_length

def get_pause_length(self):
return self.pause_length

def get_names(self):
return self.names

def get_times(self):
return self.times

def get_keys(self):
return self.keys


class Dance(object):
""" Nao robot dance. The attribute num_parts is the number of parts in the dance.
The parts attribute is a list of DanceParts"""

def __init__(self, song_name, num_parts, parts):
super(Dance, self).__init__()
self.song_name = song_name
self.num_parts = num_parts
self.parts = parts

def get_part(self, part_num):
return self.parts[part_num]

def get_song_name(self):
return self.song_name

def get_num_parts(self):
return self.num_parts

def get_parts(self):
return self.parts

  waltzDance舞蹈代码waltzDance.py

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
# -*- encoding: UTF-8 -*-

from dance import DancePart, Dance

names1 = list()
times1 = list()
keys1 = list()

names1.append("HeadPitch")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([0.136484, -0.130432, -0.147306, 0.032172, 0.0720561, 0.0720561, 0.113474, 0.00455999])

names1.append("HeadYaw")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([-0.00464392, 0.274544, 0.0122299, -0.316046, 0.00609398, 0.332836, -0.0153821, -0.43263])

names1.append("LAnklePitch")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([0.0935321, 0.0935321, 0.0843279, 0.082794, 0.082794, 0.082794, 0.082794, 0.082794])

names1.append("LAnkleRoll")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([-0.125746, -0.125746, -0.125746, -0.125746, -0.125746, -0.125746, -0.125746, -0.125746])

names1.append("LElbowRoll")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([-1.38363, -1.32533, -1.41584, -1.36062, -1.38669, -1.3192, -1.32687, -1.33914])

names1.append("LElbowYaw")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([-1.52484, -2.06634, -1.52944, -1.53711, -1.53711, -2.07248, -1.53864, -1.53864])

names1.append("LHand")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([0.2932, 0.2932, 0.2852, 0.2932, 0.2932, 0.2932, 0.2932, 0.2932])

names1.append("LHipPitch")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([0.139636, 0.139636, 0.131966, 0.139636, 0.139636, 0.139636, 0.139636, 0.139636])

names1.append("LHipRoll")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([0.093616, 0.093616, 0.10282, 0.093616, 0.093616, 0.093616, 0.093616, 0.093616])

names1.append("LHipYawPitch")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([-0.171766, -0.171766, -0.174835, -0.171766, -0.171766, -0.171766, -0.171766, -0.171766])

names1.append("LKneePitch")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([-0.0782759, -0.0782759, -0.0890141, -0.0890141, -0.0890141, -0.0890141, -0.0890141, -0.0890141])

names1.append("LShoulderPitch")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([1.50328, 1.59532, 1.50481, 1.55083, 1.54316, 1.59532, 1.47567, 1.54776])

names1.append("LShoulderRoll")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([-0.0383921, 0.338972, -0.0982179, -0.04913, -0.0890141, 0.337438, -0.107422, -0.0521979])

names1.append("LWristYaw")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([-1.49876, -1.68591, -1.5233, -1.53558, -1.53558, -1.67517, -1.52177, -1.52177])

names1.append("RAnklePitch")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([0.093616, 0.093616, 0.0874801, 0.093616, 0.093616, 0.093616, 0.093616, 0.093616])

names1.append("RAnkleRoll")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([0.135034, 0.135034, 0.127364, 0.135034, 0.135034, 0.135034, 0.135034, 0.135034])

names1.append("RElbowRoll")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([1.47575, 1.45427, 1.5095, 1.27019, 1.48189, 1.45427, 1.48189, 1.27019])

names1.append("RElbowYaw")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([1.54776, 1.56004, 1.5585, 1.33147, 1.54623, 1.5585, 1.5585, 1.32227])

names1.append("RHand")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([0.2864, 0.2864, 0.288, 0.2864, 0.2864, 0.2864, 0.2864, 0.2864])

names1.append("RHipPitch")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([0.122678, 0.122678, 0.131882, 0.133416, 0.133416, 0.133416, 0.133416, 0.133416])

names1.append("RHipRoll")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([-0.10427, -0.10427, -0.10427, -0.10427, -0.10427, -0.10427, -0.10427, -0.10427])

names1.append("RHipYawPitch")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([-0.171766, -0.171766, -0.174835, -0.171766, -0.171766, -0.171766, -0.171766, -0.171766])

names1.append("RKneePitch")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([-0.0858622, -0.0858622, -0.0873961, -0.0858622, -0.0858622, -0.0858622, -0.0858622, -0.0858622])

names1.append("RShoulderPitch")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([1.62455, 1.66597, 1.61534, 1.29781, 1.62762, 1.6629, 1.64756, 1.29781])

names1.append("RShoulderRoll")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([0.00609398, 0.0720561, 0.0628521, -0.579894, 0.0613179, 0.0613179, 0.0613179, -0.57836])

names1.append("RWristYaw")
times1.append([0.56, 1.76, 2.96, 4.24, 5.44, 6.48, 7.92, 9.56])
keys1.append([1.53549, 1.53549, 1.53703, 1.59072, 1.57231, 1.57231, 1.57231, 1.58458])

names2 = list()
times2 = list()
keys2 = list()

names2.append("HeadPitch")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([-0.147306, -0.00771189, -0.00771189, -0.147306, -0.0322559, -0.147306, -0.147306])

names2.append("HeadYaw")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([0.0122299, 0.54913, 0.54913, 0.0137641, -0.589098, 0.0137641, 0.0137641])

names2.append("LAnklePitch")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([0.0843279, 0.082794, 0.082794, 0.0843279, 0.082794, 0.0843279, 0.0843279])

names2.append("LAnkleRoll")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([-0.125746, -0.125746, -0.125746, -0.125746, -0.125746, -0.125746, -0.125746])

names2.append("LElbowRoll")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([-1.38669, -0.87127, -0.87127, -0.952573, -0.937232, -1.04308, -1.04308])

names2.append("LElbowYaw")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([-1.55245, -1.97123, -1.97123, -0.50166, -0.492456, -0.622845, -0.622845])

names2.append("LHand")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([0.2852, 0.2932, 0.2932, 0.2852, 0.2932, 0.2852, 0.2852])

names2.append("LHipPitch")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([0.131966, 0.139636, 0.139636, 0.131966, 0.139636, 0.131966, 0.131966])

names2.append("LHipRoll")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([0.10282, 0.093616, 0.093616, 0.10282, 0.093616, 0.10282, 0.10282])

names2.append("LHipYawPitch")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([-0.174835, -0.171766, -0.171766, -0.174835, -0.171766, -0.174835, -0.174835])

names2.append("LKneePitch")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([-0.0890141, -0.0890141, -0.0890141, -0.0890141, -0.0890141, -0.0890141, -0.0890141])

names2.append("LShoulderPitch")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([1.53242, 1.74872, 1.74872, -1.13827, -1.10145, 0.472429, 0.472429])

names2.append("LShoulderRoll")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([-0.0245859, 0.700996, 0.700996, 0.29602, 0.314428, 0.118076, 0.118076])

names2.append("LWristYaw")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([-1.54018, -1.42666, -1.42666, -1.12293, -1.14134, -0.785451, -0.785451])

names2.append("RAnklePitch")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([0.0874801, 0.093616, 0.093616, 0.0874801, 0.093616, 0.0874801, 0.0874801])

names2.append("RAnkleRoll")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([0.127364, 0.135034, 0.135034, 0.127364, 0.135034, 0.127364, 0.127364])

names2.append("RElbowRoll")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([1.09992, 1.11679, 1.0585, 1.06771, 0.61671, 0.60904, 0.880559])

names2.append("RElbowYaw")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([0.651908, 0.662646, 0.335904, 0.346642, 0.944902, 0.961776, 0.645772])

names2.append("RHand")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([0.288, 0.2864, 0.2864, 0.288, 0.2864, 0.288, 0.288])

names2.append("RHipPitch")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([0.131882, 0.133416, 0.133416, 0.131882, 0.133416, 0.131882, 0.131882])

names2.append("RHipRoll")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([-0.10427, -0.10427, -0.10427, -0.10427, -0.10427, -0.10427, -0.10427])

names2.append("RHipYawPitch")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([-0.174835, -0.171766, -0.171766, -0.174835, -0.171766, -0.174835, -0.174835])

names2.append("RKneePitch")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([-0.0873961, -0.0858622, -0.0858622, -0.0873961, -0.0858622, -0.0873961, -0.0873961])

names2.append("RShoulderPitch")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([-1.03081, -0.990922, 0.475582, 0.457173, 0.512398, 0.506262, 0.464844])

names2.append("RShoulderRoll")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([-0.366667, -0.391212, -0.181054, -0.170316, -0.951122, -0.981802, -0.0353239])

names2.append("RWristYaw")
times2.append([0.8, 1.76, 3.04, 4.24, 5.96, 6.76, 8.2])
keys2.append([1.75025, 1.73031, 1.38976, 1.35755, 1.06609, 1.02927, 0.812978])

names3 = list()
times3 = list()
keys3 = list()

names3.append("HeadPitch")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([-0.142704, -0.1335, 0.0904641, -0.154976, -0.0629361, -0.142704, -0.115092, -0.142704, -0.115092, -0.142704, -0.142704, 0.00455999])

names3.append("HeadYaw")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([-0.00310993, -0.00157595, 0.00609398, -0.00157595, -0.016916, 0.00762796, 0.377322, 0.00762796, -0.527738, 0.00762796, 0.00762796, 0.309826])

names3.append("LAnklePitch")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([0.0858622, 0.082794, 0.0858622, 0.082794, 0.0858622, 0.0858622, -0.259288, 0.0858622, 0.105804, 0.0858622, 0.0858622, 0.0919981])

names3.append("LAnkleRoll")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([-0.130348, -0.125746, -0.130348, -0.125746, -0.130348, -0.130348, -0.0935321, -0.130348, -0.128814, -0.131882, -0.131882, -0.128814])

names3.append("LElbowRoll")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([-1.42965, -0.056716, -1.40357, -0.0689881, -1.52169, -0.961776, -0.0475121, -0.961776, -0.954106, -1.18114, -1.4772, -1.3959])

names3.append("LElbowYaw")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([-0.506262, -0.53234, -0.495524, -1.13674, -0.329852, -0.704148, -0.757838, -0.704148, -0.68574, -1.37451, -1.49569, -2.07401])

names3.append("LHand")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([0.2932, 0.2892, 0.2892, 0.2892, 0.2892, 0.2932, 0.2892, 0.2932, 0.2892, 0.2932, 0.2932, 0.2892])

names3.append("LHipPitch")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([0.131966, 0.124296, 0.128898, 0.124296, 0.128898, 0.131966, 0.128898, 0.131966, 0.0813439, 0.130432, 0.130432, 0.121228])

names3.append("LHipRoll")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([0.096684, 0.092082, 0.096684, 0.092082, 0.096684, 0.096684, 0.096684, 0.0966839, 0.096684, 0.090548, 0.090548, 0.096684])

names3.append("LHipYawPitch")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([-0.1733, -0.179436, -0.171766, -0.179436, -0.171766, -0.1733, -0.171766, -0.1733, -0.228524, -0.171766, -0.171766, -0.170232])

names3.append("LKneePitch")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([-0.0874801, -0.092082, -0.0859461, -0.092082, -0.0859461, -0.0874801, 0.283748, -0.0874801, -0.0828779, -0.0859461, -0.0859461, -0.0828779])

names3.append("LShoulderPitch")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([1.53089, 1.55697, 1.53703, 1.48794, 0.506178, -1.0539, -0.949588, -1.0539, -1.01708, 1.37902, 1.49868, 1.53549])

names3.append("LShoulderRoll")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([0.720938, 1.09063, 0.714802, 0.607422, 0.489304, 0.408002, 1.12131, 0.408002, 0.432546, 0.542994, -0.07214, 0.0383081])

names3.append("LWristYaw")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([-1.11679, -1.1306, -1.12907, -1.8209, -1.29934, -1.11219, -1.24718, -1.11219, -1.126, -1.58006, -1.54785, -1.63835])

names3.append("RAnklePitch")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([0.09515, 0.093616, 0.0874801, 0.093616, 0.0874801, 0.093616, 0.0567999, 0.093616, -0.0689881, 0.092082, 0.092082, 0.0890141])

names3.append("RAnkleRoll")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([0.128898, 0.122762, 0.130432, 0.122762, 0.130432, 0.128898, 0.153442, 0.128898, 0.067538, 0.130432, 0.130432, 0.122762])

names3.append("RElbowRoll")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([1.4282, 0.0844119, 1.40519, 0.0598679, 1.5187, 0.978734, 1.00021, 0.978734, 0.0583339, 0.975666, 1.4374, 1.40979])

names3.append("RElbowYaw")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([0.179436, 0.19631, 0.1733, 0.872804, 0.207048, 0.573674, 0.561402, 0.573674, 0.573674, 1.10444, 1.49868, 1.48334])

names3.append("RHand")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([0.2864, 0.2916, 0.2916, 0.2916, 0.2916, 0.2864, 0.2916, 0.2864, 0.2916, 0.2864, 0.2864, 0.2916])

names3.append("RHipPitch")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([0.131882, 0.125746, 0.124212, 0.125746, 0.124212, 0.121144, 0.184038, 0.121144, -0.190258, 0.118076, 0.118076, 0.118076])

names3.append("RHipRoll")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([-0.099668, -0.0966001, -0.10427, -0.0966001, -0.10427, -0.099668, -0.12728, -0.0996681, -0.0919981, -0.0950661, -0.0950661, -0.102736])

names3.append("RHipYawPitch")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([-0.1733, -0.179436, -0.171766, -0.179436, -0.171766, -0.1733, -0.171766, -0.1733, -0.228524, -0.171766, -0.171766, -0.170232])

names3.append("RKneePitch")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([-0.0858622, -0.0889301, -0.0858622, -0.0889301, -0.0858622, -0.0858622, -0.0858622, -0.0858622, 0.335988, -0.0923279, -0.0919981, -0.0889301])

names3.append("RShoulderPitch")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([1.34843, 1.32388, 1.38064, 1.31008, 0.526204, -1.10137, -1.06916, -1.10137, -1.06916, 1.13674, 1.4466, 1.45888])

names3.append("RShoulderRoll")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([-0.794654, -1.09072, -0.77778, -0.635118, -0.553816, -0.49399, -0.513932, -0.493989, -1.09225, -0.675002, -0.046062, -0.046062])

names3.append("RWristYaw")
times3.append([0.48, 1, 1.48, 2, 3, 4.28, 5.48, 6.8, 8.08, 9.16, 10.68, 11.8])
keys3.append([1.13665, 1.34834, 1.12438, 1.82387, 1.25784, 1.13512, 1.16887, 1.13512, 1.47567, 1.22716, 1.67969, 1.66588])

names4 = list()
times4 = list()
keys4 = list()

names4.append("HeadPitch")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([0.133416, 0.131882, -0.142704, -0.142704, -0.142704, 0.12728, -0.142704, -0.142704])

names4.append("HeadYaw")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([0.0199001, -0.305308, 0.00916195, 0.00916195, 0.00916195, -0.0399261, 0.00916195, 0.00916195])

names4.append("LAnklePitch")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([0.0919981, 0.08126, 0.0858622, 0.0858622, 0.0858622, 0.0919981, 0.0413761, 0.0858622])

names4.append("LAnkleRoll")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([-0.128814, -0.128814, -0.131882, -0.131882, -0.131882, -0.128814, -0.121144, -0.131882])

names4.append("LElbowRoll")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([-1.38363, -1.38363, -1.26551, -1.27471, -0.0904641, -0.0659201, -0.049046, -0.049046])

names4.append("LElbowYaw")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([-1.3607, -1.3607, -2.07554, -2.07554, -2.08567, -0.446436, -0.42496, -0.441834])

names4.append("LHand")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([0.2892, 0.2892, 0.2932, 0.2932, 0.2932, 0.2892, 0.2932, 0.2932])

names4.append("LHipPitch")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([0.131966, 0.131966, 0.130432, 0.130432, 0.130432, 0.131966, -0.31903, 0.130432])

names4.append("LHipRoll")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([0.096684, 0.096684, 0.090548, 0.090548, 0.090548, 0.0997519, 0.024586, 0.090548])

names4.append("LHipYawPitch")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([-0.170232, -0.170232, -0.171766, -0.171766, -0.171766, -0.167164, -0.268408, -0.171766])

names4.append("LKneePitch")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([-0.0828779, -0.0828779, -0.0859461, -0.0859461, -0.0859461, -0.0828779, -0.0859461, -0.0859461])

names4.append("LShoulderPitch")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([1.49561, 1.49561, 1.50635, 0.662646, 0.673384, 1.44192, 1.36982, 1.43271])

names4.append("LShoulderRoll")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([-0.131966, -0.131966, 0.285282, 1.12745, 1.0891, 0.099668, 0.161028, 0.107338])

names4.append("LWristYaw")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([-1.7396, -1.7396, -1.67977, -1.67977, -1.68284, -1.39138, -1.37604, -1.40825])

names4.append("RAnklePitch")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([0.0890141, 0.0890141, 0.092082, 0.092082, 0.092082, 0.09515, 0.093616, 0.092082])

names4.append("RAnkleRoll")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([0.122762, 0.122762, 0.130432, 0.130432, 0.130432, 0.119694, 0.128898, 0.130432])

names4.append("RElbowRoll")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([1.33922, 1.32849, 1.33616, 1.34843, 0.268492, 0.23321, 0.21787, 0.217869])

names4.append("RElbowYaw")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([1.48334, 2.07086, 2.08567, 2.07546, 2.08567, 0.431012, 0.506178, 0.423342])

names4.append("RHand")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([0.2916, 0.2916, 0.2864, 0.2864, 0.2864, 0.2916, 0.2864, 0.2864])

names4.append("RHipPitch")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([0.118076, 0.118076, 0.118076, 0.118076, 0.118076, 0.124212, -0.415756, 0.118076])

names4.append("RHipRoll")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([-0.102736, -0.102736, -0.0950661, -0.0950661, -0.0950661, -0.10427, -0.0674541, -0.095066])

names4.append("RHipYawPitch")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([-0.170232, -0.170232, -0.171766, -0.171766, -0.171766, -0.167164, -0.268408, -0.171766])

names4.append("RKneePitch")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([-0.0889301, -0.0889301, -0.0919981, -0.0919981, -0.0919981, -0.078192, -0.0919981, -0.0812599])

names4.append("RShoulderPitch")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([1.47115, 1.49262, 1.48956, 0.89283, 0.89283, 1.50643, 1.32542, 1.5141])

names4.append("RShoulderRoll")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([0.139552, -0.216336, -0.23321, -1.19963, -1.0539, -0.200996, -0.250084, -0.211735])

names4.append("RWristYaw")
times4.append([1.36, 2.68, 4, 5.36, 6.8, 8.28, 9.6, 10.8])
keys4.append([1.66588, 1.4726, 1.44038, 1.3913, 1.70883, 1.52475, 1.50941, 1.50941])

part1 = DancePart(10, 3, names1, times1, keys1)
part2 = DancePart(8, 2, names2, times2, keys2)
part3 = DancePart(13, 4, names3, times3, keys3)
part4 = DancePart(12, 0, names4, times4, keys4)

parts = [part1, part2, part3, part4]

waltz = Dance("Waltz", 4, parts)

  具体调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from naoqi import ALProxy
import waltzDance
import time

motion = ALProxy("ALMotion", NaoIP, Port)
def dance(danceName):
for i in range(danceName.get_num_parts()):
motion.angleInterpolation(danceName.get_part(i).get_names(),
danceName.get_part(i).get_keys(),
danceName.get_part(i).get_times(), True)
# time.sleep(danceName.get_part(i).get_pause_length())
time.sleep(0.3)

waltz = waltzDance.waltz
dance(waltz)

  当然也可以设计其他的舞蹈动作。

多线程实现边唱歌边跳舞

利用python实现

  python中有专门的多线程模块threading,我们可以把跳舞作为主线程,唱歌作为一个子线程,在跳舞的同时,开启一个线程专门来播放音频,即可实现边唱歌边跳舞。
  首先创建个线程的对象,然后用start()函数来开启该线程。

1
2
3
import threading
mythread = threading.Thread(target=function_name, args=(function_parameter1, ))
mythread.start()

  创建对象时,第一个参数是目标函数的函数名(不是调用,不需要加括号),第二个参数是目标函数的参数,是可选参数,用元组的形式将参数封装起来,如果只有1个参数,后面的逗号不可以省略。然后调用start()开启线程。

1
2
3
4
t1 = threading.Thread(target=playMusic)

t1.start()
dance.dance(waltz)

利用模块的post属性实现

  除了python的多线程可以实现此功能之外,ALAudioPlayer类中的post属性也可以实现。
  在NAOqi模块的一些持续性动作的类中,比如播放音频的ALAudioPlayer类的playFile(),运动类ALMotion中的moveTo(),都有一个post属性。所谓post属性就是将这个持续性动作的进程挂起,NAO可以在执行这个进程的同时进行其他的操作。其调用方式为在playFile()函数前加上.post

1
2
3
audio = ALProxy("ALAudioPlayer", '169.254.67.213', 9559)
songfile = "/home/nao/test/test_wav.wav"
audio.post.playFile(songfile)

  在post语句下面可以添加其他的功能,此时NAO会一直播放音频文件,并执行下面的语句,直到音频文件播放完毕。例如实现边跳舞边唱歌,只需在playFile()函数前加上post,然后在下面调用dance()函数。

1
2
3
def danceAndSong(danceName, songName):
audio.post.playFile(songName)
dance()

  除了播放音频的库可以加post之外,行走库中的moveTo()也可以,即可以实现边行走边执行其他的模块,比如边行走边调用NAO的视觉系统,例如我的另一篇博客:NAO高尔夫比赛:python初级版

开机自启动边跳舞边唱歌

  如果想实现开机自启动某个程序,需要更改NAO的开机启动配置文件,其文件路径为/home/nao/naoqi/preferences/autoload.ini。使用Choregraph软件或者WinSCP软件将其下载到本地计算机中,然后使用VScode或其他编译器软件打开,找到其中的[python],然后将需要启动的py文件路径放在下一行,重新启动NAO机器人就会自动执行该文件。
  需要将python文件中的IP地址改为NAO的本地IP,即"127.0.0.1"

附:Choregraph实现开机自启动

  首先新建一个项目文件,编写代码。例如我写了一个说“hello world”的程序,命名为hello。

  然后保存并上传到机器人系统中,上传功能在应用程序视图。

  在应用程序中找到你的文件,并右击设置为默认状态。会出现一个小旗子。最后重启机器人,就会进入你写的程序中。

  注:NAO机器人开机后会进入自主模式,即开机后会站立并来回晃动。这个好像去不掉,可以在你写的代码里面进行处理。我实际测试下来,需要等待一段时间才会进入到开机自启动的项目中。

谢谢老板!
-------------本文结束感谢您的阅读给个五星好评吧~~-------------