All posts by chen

Donkey Car1 -用DIY机器人构建AI社区

用DIY机器人构建AI社区:第1部分 – 驴车

使用DIY机器人构建AI社区

这是关于Donkey Car的3部分系列中的第一部。以下是第2 部分第3 部分的链接。

我已经通过CoderDojo计划建立了用于教孩子计算机科学近四年的机器人。这是一次有益的经历,我学到了很多关于构建Arduino套件和简单机器人的知识。我一直在为8-18岁的孩子创造“学习阶梯”,而我的机器人则被5岁以下的儿童在The Works Museum使用。围绕DIY项目构建STEM课程很有趣,也是寻找社区的好方法。你可以在Moving RainbowCoderDojo Robots网站上看到我的一些工作。

随着新的一年,我决定扩展我的舒适区,包括基于Raspberry Pi,Python和机器学习的更复杂的机器人。我的朋友Arun Batchu也通过购买非常酷的NVIDIA Jetson Xavier开发套件来鼓励这一点。不幸的是,我的小机器人不足以运行这个价值90亿的晶体管系统。我认为这对我来说是一个很好的方式来了解最新的图像识别和边缘计算的热门话题。建立一个本地DIY机器人小组也是在明尼阿波利斯地区建立一个更强大的AI社区的一种方式。

对于那些不熟悉Donkey Car项目的人来说,它是一个开源DIY项目,让人们学习实时图像识别和一些AI的基础知识。这辆车的零件大约250美元。这比我的Arduino机器人贵10倍,但它也更强大。在湾区,有超过2,500人参加了DIY Robocars聚会,Donkey Car Slack工作区几乎有多少人在汽车,赛道,算法,机器学习模型和相关主题上有数千个帖子。我们在明尼苏达州还没有像这样的社区,但我希望改变这个!

以下是我开始制作驴车的工作日记。所以他们说…我们参加了比赛!

我在Swarm64的伟大人物的最后一次MinneAnalytics会议上“天赋”了一个Raspberry Pi 3 B + Kit,其中包括Paul McCullugh和Thomas Richter。Swarm64使用FPGA为RDBMS系统提供了出色的加速器。如果你需要一个更快的关系数据库给他们一个电话!

Raspberry Pi套件包括带有PI OS的32GB micro SD卡,电源砖,GPIO分线器以及外壳以及其他一些部件。我添加了一个27美元的SainSmart广角鱼眼摄像头和一个PCA9685 16通道12位PWM伺服电机驱动器以及一辆新的90美元RC车(我还没有测试过)。我使用GPIO使用Thonny Python IDE对LED进行了闪烁测试,并找到了用于控制LED灯条的DMA库。我还在圣路易斯公园的Microcenter购买了两张额外的32GB SD卡,每张 4.99美元。这比我在亚马逊上找到的要少。微中心真的很摇滚!我建议你买几张微型SD卡,这样你就可以进行备份了。

在Arduino的“C / C ++”工作多年之后,我对Pi开始的难度感到有些惊讶。有许多库需要以正确的顺序安装,需要考虑许多版本的Python。Thonney Python IDE很不错,但它缺少我们需要用TensorFlow认真工作的大多数库。好消息是,一旦库设置编码变得非常快。如果您正在使用物理设备进行硬件编程,那么当您对代码进行更改并且必须将其上传到Arduino时,就没有“滞后”。程序立即运行!我认为这可以加快开发速度,特别是当你有大型程序时。

现在进入Donkey Car … Donkey Car网站做得非常好,但它假设UNIX和Pi的背景非常强大。当他们发出指示时,我不清楚我应该在我的新Pi或远程计算机上运行。我花了大约两天时间试图让各种Python和TensorFlow库在Pi上本地工作。虽然我在进步中学到了很多东西,但事实证明这是一个死路一条。只有2GB或RAM的Pi太小了,无法在没有英雄努力的情况下编译庞大的TensorFlow-Keras系统。即使在具有16GB内存的Mac上,我也遇到了基于Bazel的TensorFlow编译系统的bug。Bazel构建框架本身非常复杂,您需要Bazel来编译TensorFlow怪物。做只是没有削减它。我正要放弃。如果像我这样拥有25年UNIX经验的人无法安装这个东西,我怎么能希望培养我14岁的学生呢?

然后我开始意识到,在Donkey汽车上完成的所有事情都假设了一个无头Pi(没有监视器,只是一个SSH访问),并使用他们的磁盘映像,这些映像由Linux和Pi专家精心制作了三年。你需要启动他们的Pi图像,其他一切都有效!你不能将Pi用作开发系统。TensorFlow文档确实这样说,但我没有RTFM。

我努力了解如何基于Donkey图像(包含磁盘映像的zip文件)为Pi构建启动映像。在尝试了NOOBS系统后,我意识到balenaEtcher应用程序正是我所需要的。该应用程序在Windows或Mac上使用非常简单。您只需从Donkey Car网站下载图像zip文件,将新SD卡放入并运行belenaEtcher应用程序。它会提示您输入图像文件(无需解压缩zip文件),它会自动找到SD驱动器然后我点击“Flash”。噗!在短短几分钟内,我就有了经过验证的磁盘映像。

重新启动新SD到我的Pi后,我可以登录并更改wifi设置。再一次重启,我准备好进入我的新驴车。我还设置了静态IP地址,因此每次都会重新连接到同一个IP地址。“/ home / pi / env”目录下的文件计数显示了近13,000个文件。如果你想的复杂细节我把它们放在一个启用评论,谷歌文档文件在这里。随意为该文件添加注释。

我将在发布更新时发布更新,并在其他部分到达后发布。我需要它们来做校准步骤。

Webduino Smart Car

Webduino Smart 自走車

 

Smart 自走車 ( 組裝步驟 )

Smart 自走車是 Webduino 自主研發的產品,專為 Smart 開發板量身打造,輕巧、方便又環保!不僅能 DIY 動手玩創意,還能輕鬆學習程式邏輯概念,實作出一台具個人特色的自走車。

https://tutorials.webduino.io/zh-tw/docs/useful/example/smart-robot-car-assembly.html

支援無線控制,隨心所欲、輕鬆把玩

 

Smart 自走車 ( 網頁遙控器操控 )

Smart 自走車是 Webduino 自主研發的產品,專為 Smart 開發板量身打造,輕巧、方便又環保!這個範例我們會實作如何透過網頁遙控器 ( 電腦、平板、手機皆可 ),就能操控自走車。

https://tutorials.webduino.io/zh-tw/docs/useful/example/smart-robot-car-remote-control.html

只要搭配 Webduino 雲端平台,就能輕鬆實現多種絕佳應用,最棒的是手機、平板 ( IOS / Android )、電腦都能使用!

Smart 自走車 – 網頁操控,積木程式範例:https://goo.gl/432ZRW

超音波傳感器避障小車

Webduino Smart 自走車可以搭配超過 10 種以上的傳感器, 發展出各式各樣驚奇的功能,例如無線遙控車、避障車、溫濕度感測車、無人車等多項應用,自己玩創意。

下圖為結合基礎套件裡頭的超音波傳感器,自製避障小車,當偵測到障礙物就能自動後退並改道!超音波避障車,積木程式教學範例:https://goo.gl/CXzuYT

 Smart 溫濕度感測車

這是加入「溫濕度傳感器」及 「Google 試算表」的應用,實現隨時隨地將環境溫濕度資料儲存在雲端,實作一台 Smart 溫濕度感測車,積木程式教學範例:https://goo.gl/CXzuYT

WeMos Smart Car Motor Shield

学園祭のため、IoTぼいのスマート車を作る。

しかし、注文したMotor Shield とは、違うもの(base only)が来たので、急遽自作する。

そのためのコントロールするAppも作りたいが、時間がなくって、ネットからWebページでコントロールするものを探して、沢山手直して、動くようになった。

車数台用意して、各車のIPは固定にしたいので、WiFiManager使わない方法をとった。

Webページでコントロールするから、遅延は目たつ。

時間があったら、ちゃんとアクセルペダルなど追加して、アプリの形にしたい。

// include libraries
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

#define motor_lf D3
#define motor_lb D4
#define motor_rf D6
#define motor_rb D5

// configure server
ESP8266WebServer server(80);
const char *form = "<!DOCTYPE HTML>"
"<meta name='viewport' content='width=device-width'>"
"<html>"
"<center><form action='/'>"
"<button name='dir' type='submit' value='4'>Forward</button><p>"
"<button name='dir' type='submit' value='1'>Left</button> "
"<button name='dir' type='submit' value='2'>Right</button><p>"
"<button name='dir' type='submit' value='3'>Reverse</button><p><p>"
"<button name='dir' type='submit' value='5'>Stop</button>"
"</form></center>"
"</html>";
void stop(void)
{
    analogWrite(motor_lf, 0);
    analogWrite(motor_lb, 0);
    analogWrite(motor_rf, 0);
    analogWrite(motor_rb, 0);
}
void forward(void)
{
    analogWrite(motor_lf, 1023);
    analogWrite(motor_lb, 0);
    analogWrite(motor_rf, 1023);
    analogWrite(motor_rb, 0);
}
void backward(void)
{
    analogWrite(motor_lf, 0);
    analogWrite(motor_lb, 1023);
    analogWrite(motor_rf, 0);
    analogWrite(motor_rb, 1023);
}
void left(void)
{
    analogWrite(motor_lf, 0);
    analogWrite(motor_lb, 0);
    analogWrite(motor_rf, 1023);
    analogWrite(motor_rb, 0);
}
void right(void)
{
    analogWrite(motor_lf, 1023);
    analogWrite(motor_lb, 0);
    analogWrite(motor_rf, 0);
    analogWrite(motor_rb, 0);
}
void handle_form()
{
    // only move if we submitted the form
    if (server.arg("dir"))
    {
        // get the value of request argument "dir"
        int direction = server.arg("dir").toInt();
        // chose direction
        switch (direction)
        {
            case 1:
                left();
                break;
            case 2:
                right();
                break;
            case 3:
                backward();
                break;
            case 4:
                forward();
                break;
            case 5:
                stop();
                break;
        }
        // move for 300ms, gives chip time to update wifi also
        delay(300);
    }
    
    // in all cases send the response
    server.send(200, "text/html", form);
}
void setup()
{
    // connect to wifi network
    WiFi.begin("uislab003", "**password**");
    // static ip, gateway, netmask
    WiFi.config(IPAddress(192,168,11,10), IPAddress(192,168,11,1), IPAddress(255,255,255,0));
    // connect
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(200);
    }
  
    // set up the callback for http server
    server.on("/", handle_form);
    // start the webserver
    server.begin();
    pinMode(motor_lf, OUTPUT); // 
    pinMode(motor_lb, OUTPUT); // 
    pinMode(motor_rf, OUTPUT); // 
    pinMode(motor_rb, OUTPUT); // 

}
void loop()
{
    // check for client connections
    server.handleClient();
}