入门篇(4)NAO机器人接力赛通信问题

一、前言

NAO机器人接触有一年多了,期间开发了很多的程序。

—最开始是做NAO机器人人脸识别和室内复杂环境下的路径规划;

—后来参加NAO机器人高尔夫球赛,开发了一套完整的NAO 机器人打高尔夫球赛的框架,并将源码提供给了举办方。

—在此基础之上,又帮助举办方开发了一套NAO机器人接力赛程序框架。第一个版本是机器人通过Socket通信实现机器人消息传输,也是本章节提及的;第二个版本为机器人通过机器视觉来提取信息。

下面就来说说socket通信吧。
socket通信
TCP服务端:
1 创建套接字,绑定套接字到本地IP与端口
# socket.socket(socket.AF_INET,socket.SOCK_STREAM) , s.bind()
2 开始监听连接 #s.listen()
3 进入循环,不断接受客户端的连接请求 #s.accept()
4 然后接收传来的数据,并发送给对方数据 #s.recv() , s.sendall()
5 传输完毕后,关闭套接字 #s.close()

TCP客户端:
1 创建套接字,连接远端地址
# socket.socket(socket.AF_INET,socket.SOCK_STREAM) , s.connect()
2 连接后发送数据和接收数据 # s.sendall(), s.recv()
3 传输完毕后,关闭套接字 #s.close()

对于NAO机器人,无非就是一个作为服务器,一个作为客户端,代码如下:
client.py

#-*- coding: utf-8 -*-
###########################################################
#   > Description:      远程控制-客户端
#                       向服务器发送指令,查看服务器回执消息。
###########################################################
#! /usr/bin/env python

import argparse
from naoqi import ALProxy
import socket
import time

LISTEN_PORT = 8001 # 服务器监听端口

# command 
COMMAND_DISCONNECT = 'DISCONNECT'
COMMAND_HEADYAW = 'HEADYAW'     # 头左右
COMMAND_HEADPITCH = 'HEADPITCH' # 头上下

# flag
CONNECT = False

def main(robot_IP, robot_PORT=9559):
    # ----------> 连接socket服务器监听端口 <----------
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((robot_IP, LISTEN_PORT))
    time.sleep(2)

    CONNECT = True
    while CONNECT == True: 
        # 输入指令
        command = raw_input("Command code:")
        # socket 发送指令
        sock.send(command)
        if command == COMMAND_HEADYAW or command == COMMAND_HEADPITCH:
            value = raw_input("Value:")
            sock.send(value)

        # socket 接受返回消息
        buf = sock.recv(1024)
        print buf
        if command == COMMAND_DISCONNECT: 
            CONNECT = False
    sock.close() # 与服务器端断开socket连接

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--ip", type=str, default="192.168.1.100", help="Robot ip address")
    parser.add_argument("--port", type=int, default=9559, help="Robot port number")
    args = parser.parse_args()
    # ----------> 执行main函数 <----------
    main(args.ip, args.port)

server.py

#! /usr/bin/env python
#-*- coding: utf-8 -*-
###########################################################
#   > Description:      远程控制-服务器端
#                       接受客户端发来的指令,执行相应功能。
###########################################################
import argparse
from naoqi import ALProxy
import socket
import sys      # sys.exit() 退出main函数
import almath   # 角度转弧度(almath.TO_RAD)
import thread   # 多线程
import time     # 延时函数 time.sleep(1)

LISTEN_PORT = 8001 # 服务器监听端口

# Command 定义
COMMAND_WAKEUP = 'WAKEUP'
COMMAND_REST = 'REST'

COMMAND_FORWARD = 'FORWARD'
COMMAND_BACK = 'BACK'
COMMAND_LEFT = 'LEFT'
COMMAND_RIGHT = 'RIGHT'
COMMAND_STOP = 'STOP'

COMMAND_TURNLEFT = 'TURNLEFT'
COMMAND_TURNRIGHT = 'TURNRIGHT'

COMMAND_DISCONNECT = 'DISCONNECT'
COMMAND_SENSOR = 'SENSOR'

COMMAND_HEADYAW = 'HEADYAW'     # 头左右
COMMAND_HEADPITCH = 'HEADPITCH' # 头上下

# flag
CONNECT = False         # 客户端连接Flag 
SENSOR  = False         # 传感器监控Flag, 为True则有线程定时发送数据;

# 全局变量,供其他函数使用
ROBOT_IP = '192.168.1.100'
ROBOT_PORT = 9559
connection = None
battery = None
memory = None

def main(robot_IP, robot_PORT=9559):

    global ROBOT_IP
    global ROBOT_PORT
    ROBOT_IP = robot_IP
    ROBOT_PORT = robot_PORT

    # ----------> Connect to robot <----------
    tts = ALProxy("ALTextToSpeech", robot_IP, robot_PORT)
    motion = ALProxy("ALMotion", robot_IP, robot_PORT)
    posture = ALProxy("ALRobotPosture", robot_IP, robot_PORT)
    global memory
    memory = ALProxy("ALMemory", robot_IP, robot_PORT)
    leds = ALProxy("ALLeds", robot_IP, robot_PORT)
    global battery
    battery = ALProxy("ALBattery", ROBOT_IP, ROBOT_PORT)
    autonomous = ALProxy("ALAutonomousLife", robot_IP, robot_PORT)
    autonomous.setState("disabled") # turn ALAutonomousLife off

    # ----------> 开启socket服务器监听端口 <----------
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind((robot_IP, LISTEN_PORT))
    sock.listen(10)

    try:
        while True: # 等待客户端连接,单线程监听单一客户端
            global connection
            connection,address = sock.accept()
            CONNECT = True
            while CONNECT == True:
                try:
                    #connection.settimeout(10)
                    # 服务器接受指令
                    buf = connection.recv(1024)
                    print "get:[", buf, "]"
                    # 根据接受的命令执行不同操作
                    if buf == COMMAND_WAKEUP:
                        if motion.robotIsWakeUp() == False: 
                            motion.post.wakeUp()
                        connection.send("Robot Motion: [ Wakeup ]\r")
                    elif buf == COMMAND_REST:
                        if motion.robotIsWakeUp() == True: 
                            motion.post.rest()
                        connection.send("Robot Motion: [ Rest ]\r")
                    elif buf == COMMAND_FORWARD:
                        if motion.robotIsWakeUp() == False: 
                            motion.post.wakeUp()
                            connection.send("Robot Motion: [ Wakeup ]\r")
                            motion.post.moveInit()
                            connection.send("Robot Motion: [ MoveInit ]\r")
                        #motion.post.moveTo(0.3, 0, 0)
                        motion.move(0.1,0,0) # 固定速率持续行走
                        connection.send("Robot Motion: [ Forward ]\r")
                    elif buf == COMMAND_BACK:
                        if motion.robotIsWakeUp() == False: 
                            motion.post.wakeUp()
                            connection.send("Robot Motion: [ Wakeup ]\r")
                            motion.post.moveInit()
                            connection.send("Robot Motion: [ MoveInit ]\r")
                        #motion.post.moveTo(-0.1, 0, 0)
                        motion.move(-0.1,0,0)
                        connection.send("Robot Motion: [ Back ]\r")
                    elif buf == COMMAND_LEFT:
                        if motion.robotIsWakeUp() == False: 
                            motion.post.wakeUp()
                            connection.send("Robot Motion: [ Wakeup ]\r")
                            motion.post.moveInit()
                            connection.send("Robot Motion: [ MoveInit ]\r")
                        #motion.post.moveTo(0, 0.1, 0)
                        motion.move(0,0.1,0)
                        connection.send("Robot Motion: [ Left ]\r")
                    elif buf == COMMAND_RIGHT:
                        if motion.robotIsWakeUp() == False: 
                            motion.post.wakeUp()
                            connection.send("Robot Motion: [ Wakeup ]\r")
                            motion.post.moveInit()
                            connection.send("Robot Motion: [ MoveInit ]\r")
                        #motion.post.moveTo(0, -0.1, 0)
                        motion.move(0,-0.1,0)
                        connection.send("Robot Motion: [ Right ]\r")
                    elif buf == COMMAND_STOP:
                        motion.stopMove()
                        connection.send("Robot Motion: [ stop move ]\r")
                    elif buf == COMMAND_TURNRIGHT:
                        if motion.robotIsWakeUp() == False: 
                            motion.post.wakeUp()
                            connection.send("Robot Motion: [ Wakeup ]\r")
                            motion.post.moveInit()
                            connection.send("Robot Motion: [ MoveInit ]\r")
                        motion.move(0, 0, -0.3)
                        connection.send("Robot Motion: [ turn right ]\r")
                    elif buf == COMMAND_TURNLEFT:
                        if motion.robotIsWakeUp() == False: 
                            motion.post.wakeUp()
                            connection.send("Robot Motion: [ Wakeup ]\r")
                            motion.post.moveInit()
                            connection.send("Robot Motion: [ MoveInit ]\r")
                        motion.move(0, 0, 0.3)
                        connection.send("Robot Motion: [ turn left ]\r")
                    elif buf == COMMAND_DISCONNECT:
                        CONNECT = False
                        connection.send("disconnect from robot server.\r")
                    elif buf == COMMAND_HEADYAW:
                        # 头部左右转动(Yaw轴)
                        buf2 = connection.recv(1024)    # 读取Yaw值    
                        print "yaw:", buf2
                        angles = (int(buf2) - 50)  
                        motion.setStiffnesses("Head", 1.0)
                        motion.setAngles("HeadYaw", angles * almath.TO_RAD, 0.2) # 以10%的速度转换angles角度
                        connection.send("Robot Motion: [ head raw ]\r")
                    elif buf == COMMAND_HEADPITCH:
                        # 头部上下转动(Pitch轴)
                        buf2 = connection.recv(1024)    # 读取Pitch值  
                        print "pitch:", buf2
                        angles = (int(buf2) - 50) * 2
                        motion.setStiffnesses("Head", 1.0)
                        motion.setAngles("HeadPitch", angles * almath.TO_RAD, 0.2) # 以10%的速度转换angles角度
                        connection.send("Robot Motion: [ head pitch ]\r")
                    elif buf == COMMAND_SENSOR:
                        global SENSOR
                        if SENSOR == False:
                            # 开启新线程,定时发送传感器数据
                            SENSOR = True
                            thread.start_new_thread(sensor, (1,)) # 2nd arg must be a tuple
                        else:
                            # 第二次发送COMMAND_SENSOR, 则关闭线程
                            SENSOR = False  # 设置标识位,线程检测后自己退出。
                        connection.send("Robot Motion: [ send sensor value ]\r")
                    else:
                        connection.send(buf + ": command not found\r")
                except socket.timeout:
                    print 'time out'
            connection.close()  # 关闭当前socket连接,进入下一轮循环
    except KeyboardInterrupt: # CTRL+C, 关闭服务器端程序;
        print ""
        print "Interrupted by user, shutting down"
        sys.exit(0)

def sensor(interval):
    ''' 每interval秒,发送一次传感器数据
    '''
    while SENSOR == True:
        connection.send("BATTERY" + "#" + str(battery.getBatteryCharge()) + "\r")
        connection.send("SONAR1" + "#" + str(memory.getData("Device/SubDeviceList/US/Left/Sensor/Value")) + "\r")
        connection.send("SONAR2" + "#" + str(memory.getData("Device/SubDeviceList/US/Right/Sensor/Value")) + "\r")
#       print "BATTERY" + "#" + str(battery.getBatteryCharge())
        time.sleep(interval)
    # SENSOR == False
    thread.exit_thread()       

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--ip", type=str, default="192.168.1.100", help="Robot ip address")
    parser.add_argument("--port", type=int, default=9559, help="Robot port number")
    args = parser.parse_args()
    # ----------> 执行main函数 <----------
    main(args.ip, args.port)

第一台机器人到达终点立即给第二台机器人发一个指令即可。接力跑还是很容易啊。重点在‘’跑‘’!

猜你喜欢

转载自blog.csdn.net/zz683693/article/details/77507588