斗牛太危险,来斗机器人吧

2017-05-12 19:06:59 +08:00
 Vincross

摘要

这次 HEXA 不是尬舞或逗宠物那么简单了,而是学会追逐眼前的一抹红了。(孩子大了,不省心呐)。开发者利用拍照功能确认红色,并发起千里追凶。现在这个功能已经成功上架到 Vincross Skill Store,工作人员亲测任何在 HEXA 距离 1 米以内的红色物体都会引起它的亲密追逐。


我教会了 HEXA 如何斗牛

by @Heinegan 第一次看到这个小家伙的时候,就被这个六只脚的小家伙萌翻了。开箱照?实在太激动,忘拍了。现在有点后悔没记录下那一刻。 我很快下载了 App,并且玩了一会儿。它的动作太逗了,天知道我摆弄了多久。但光是玩儿还不过瘾,我觉得它还可以更好玩一些!

大概想了一刻钟我都没想出还能怎么玩。于是我改变了想法——也许我不该执着于 HEXA 能干嘛,而应该专注于我能让它干什么。 由于我之前做过一些关于计算机视觉的工作,所以我决定帮 HEXA 醒醒目。另外,我喜欢西班牙的斗牛表演,我是 coder 外表斗牛士的心,不过真要自己去尝试我这个体格肯定不行。但我们是技术派嘛,HEXA 可以当我的公牛!我可以看着它追逐红布但不会伤到我。

于是我去官网查了文档和 SDK 和文档,必须说 Vincross 干得不错。在找到了我需要的信息后,我就很快去投入创作了。

为了让 HEXA 变成公牛,我必须:

Pseudo-code 如下:

我用了 3 个 go routinue 分别控制头部转动、向前走以及监测红色。转动头部时,头部移动以及红色的检测在同一个 routinue 里面实现了。然后我将这些 go routinue 映射到几个状态。作为一个 hacking demo,这儿实现得不怎么优雅。这里建议大家看下官网给出的几个简单的示例,对快速上手 HEXA 的开发很有帮助。 https://github.com/vincross/hexa-example-skills

以下是具体的开发过程,欢迎分享你的意见。

1. 转动头部

HEXA 身体控制接口由 hexabody package 提供,注意在使用前需要调用 Start()函数,结束后调用 Stop()。Start 调用后就可以愉快地调用其他接口控制 HEXA 了。MoveHead 可以控制头部的移动,参数 degree 控制移动的角度,duration 控制移动的时间。这里吐槽下,接口文档说的是将头部移动到指定的角度,但实际上是以当前角度为参考,顺时钟移动值为‘ degree ’的角度。duration 表示需要多长时间做完这个动作,也就是决定移动的速度,但我在文档中找了一会没有找到 HEXA 转动头部的最大值.

func (skill *ScanRed) searchRed() {
    for skill.status {
        if skill.round {
            direction := hexabody.Direction()
            direction += 30
            hexabody.MoveHead(direction, 200)
            skill.checkRedLightDistrict()
            time.Sleep(time.Millisecond * 100)
        }
        time.Sleep(time.Millisecond * 200)
    }
}

2. 检测红色

多媒体接口由 Media 接口提供,同 hexabody 一样,需要调用 Start 和 Stop。我们需要用到的是 SnapshotRGBA 这个接口,它返回一张 RGBA Image。我太想看到最终的效果是怎样的,所以用了一种最简单的方式判断这张图片是否有红色。先从图片中取出中间那一部分,然后判断里面有多少个像素,大于一个阈值则认为是红色,这种方法比较笨,效率也不高,但可用。对了,这里用到了 goalng 的 image package。这部分代码如下:

 newImg := m.SubImage(subBounds)
    width := newImg.Bounds().Size().X
    height := newImg.Bounds().Size().Y
    for w := 0; w < width; w++ {
        for h := 0; h < height; h++ {
            r, g, b, _ := newImg.At(w, h).RGBA()
            r = r >> 8
            g = g >> 8
            b = b >> 8
            c := (int(r) - int(g)) + (int(r) - int(b))
            if c > thresHold {
                subRed++
            }
        }
    }
    log.Info.Printf("%d %d", subRed, width*height)
    if subRed > (width*height)/200 {
        return true
    }
    return false
}

3. 往前走

当 HEXA 检测到前方有红色时,HEXA 会停止转动头部,并且朝红色方向走去。这儿调用了 heaxbody 的 Walk 函数,很明显这个函数的方向是需要你定义的。接着吐槽下,文档里有 Moving forward one frame,但里面没有说明一步 frame 有多远.

func (skill *ScanRed) goToRed() {
    for skill.status {
        if skill.run {
            log.Info.Printf("RUN...")
            hexabody.Walk(hexabody.Direction(), 100)
        }
        else {
            time.Sleep(time.Millisecond * 200)
        }
    }
}

我大概花了一天的时间来做这个 skill,时间主要花在熟悉文档以及判断红色的算法上面。虽然上面有吐槽,但总的来说文档结构已经内容都还是非常清晰明了,非常容易看懂。

现在我的 HEXA 已经变身勇猛的“公牛”了。额,其实也许并不很猛,说它萌还差不多。接下来我会继续更新这个帖子的。但也许我还想先试试为 HEXA 发展出其他功能。


这个帖子的内容来自 Vincross (也就是我们自己)的开发者论坛。原贴是英文的,我们觉得很有意思,所以把帖子翻译成中文。 开发使用的是 Golang 语言。

文中提到的 frame 缺乏说明和示例问题,Documentation 里已经改正了~

特别说明:Vincross 拥有使用这个帖子的转载和宣传的权力。

3015 次点击
所在节点    分享创造
7 条回复
Vincross
2017-05-12 19:17:28 +08:00
谢谢 @Livid 置顶,偷偷说翻译这篇时真的想吐血。
wjm2038
2017-05-12 19:27:44 +08:00
不会翻车么
o00o
2017-05-12 19:48:26 +08:00
要不然来个视频
glume
2017-05-12 21:55:28 +08:00
持续关注中。。。。
另外,蜘蛛会跳的,这个能跳么?
Livid
2017-05-13 14:11:32 +08:00
补充个视频吧,你们有 Vimeo 频道么?
Vincross
2017-05-14 16:01:13 +08:00
@Livid 下周一我们团队自己拍一个~
Vincross
2017-05-15 16:36:26 +08:00
新鲜出炉的视频

<a href="<amp-vimeo data-videoid="217457404" layout="responsive" width="16" height="9"></amp-vimeo>" target="_blank"><img src=" "
alt="IMAGE ALT TEXT HERE" width="240" height="180" border="10" /></a>

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/360944

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX