奥松机器人

这里给大家带来一个借助角蜂鸟实现的人脸检测控制的机器人。

硬件清单参考如下:

  • 角蜂鸟
  • 树莓派3b
  • 奥松机器人
  • 12V转5V的DC-DC模块(可选)
  • 散热风扇(可选)

构思

2-1

在角蜂鸟内置的模型中,为我们提供了 Mobilenet-SSD 模型,我们将使用这个模型实现人脸检测的功能。大概的处理逻辑如下:

2-2

实现

首先组装好奥松机器人,奥松机器人为树莓派供电,树莓派为角蜂鸟供电,树莓派通过USB通信控制奥松机器人和角蜂鸟。 由于树莓派USB供电限制,可能会产生供电不足的问题,影响稳定性。这里考虑从奥松机器人的电源上接入12V转5V的DC-DC模块为USB提供额外供电,或者使用外源HUB。 担心空间散热性比较差可考虑加入散热风扇。

为了优雅与美观,这里我们DIY了奥松机器人,把所有的东西都埋进了脑袋里,角蜂鸟放在了后脑勺的位置。

3-1

奥松机器人控制代码如下:

class RapiroProcessor(Thread):

    class Flags:
        face = None
        face_frame_cnt = 0
        head_angle = 90
        arm_raised = False
        light_on = False
        light_need_change = False

    def __init__(self, connection):
        Thread.__init__(self)
        self.daemon = True
        self.rapiro = Rapiro(connection)
        self.flags = RapiroProcessor.Flags()

    def reset(self):
        self.rapiro.execute(GO_TO_INITIAL_POSITION)
        time.sleep(3)

    def run(self):
        self.reset()
        try:
            while True:
                time.sleep(0.1)
                has_face = self.flags.face is not None
                frame_cnt = self.flags.face_frame_cnt
                comm = ""
                if has_face:  # 计算头部舵机角度
                    x1 = self.flags.face[2]
                    x2 = self.flags.face[4]
                    x_mid = (x1 + x2) / 2
                    if x_mid > 0.6 or x_mid / 2 < 0.4:
                        angle = self.flags.head_angle - int((x_mid - 0.5) / 0.1)
                    else:
                        angle = self.flags.head_angle
                    angle = 180 if angle > 180 else angle
                    angle = 0 if angle < 0 else angle
                    self.flags.head_angle = angle
                    eye = (246, 124, 1)
                    frame_cnt += 1
                else:
                    eye = (2, 220, 255)
                    frame_cnt -= 1

                self.flags.light_need_change = (not has_face if self.flags.light_on else has_face)
                self.flags.light_on = has_face

                if frame_cnt > 5:  # 举起右手
                    self.flags.face_frame_cnt = 5
                    if not self.flags.arm_raised:
                        comm += r_shoulder_yz(90, 1)
                        self.flags.arm_raised = True
                elif frame_cnt < -5:  # 放下右手
                    self.flags.face_frame_cnt = -5
                    if self.flags.arm_raised:
                        comm += r_shoulder_yz(0, 1)
                        self.flags.arm_raised = False
                else:
                    self.flags.face_frame_cnt = frame_cnt

                if self.flags.light_need_change:  # 眼睛变色
                    comm += eye_color(eye[0], eye[1], eye[2], 1)
                comm += head_yaw(self.flags.head_angle, 1)

                self.rapiro.execute(comm)
        finally:
            self.reset()

角蜂鸟处理逻辑如下:

#!/usr/bin/env python3
# coding=utf-8

import sys
sys.path.append("../../SungemSDK-Python")
import hsapi as hs
import rapiro
import video


def process(ret):
    img = ret[0]
    face = []
    img_w = img.shape[1]
    img_h = img.shape[0]
    for box in ret[1]:
        if (box[4] - box[2] > img_w * 0.8) \
                and (box[5] - box[3] > img_h * 0.8):
            # 过滤网络误检
            continue
        box[2] /= img_w
        box[4] /= img_w
        box[3] /= img_h
        box[5] /= img_h
        face.append(box)
    return face


if __name__ == '__main__':
    t_rapiro = rapiro.RapiroProcessor("/dev/ttyUSB0")  # 控制线程
    t_video = video.VideoProcessor(("192.168.50.202", 10600))  # 视频线程

    try:
        net = hs.FaceDetector(zoom=True, verbose=0, threshSSD=0.55)
        t_rapiro.start()
        t_video.start()
        while True:
            result = net.run()
            image = net.plot(result)

            faces = process(result)
            t_rapiro.flags.face = faces[0] if len(faces) > 0 else None

            if t_video.has_client():
                t_video.input_queue.put(image)  # 传输视频到远端
    finally:
        t_rapiro.reset()

展示

当检测到人脸时,奥松机器人的头部会跟随转动,保持人脸在视野居中位置,举起右手,同时眼睛变为黄色;当检测不到人脸时,手臂放下,同时眼睛变为蓝色。

4-1 4-2