【DigiKey“智造万物,快乐不停”创意大赛】工地安全检测移动装置
项目背景
随着工业化进程的加速和建筑业的发展,机器人在工业和建筑领域的应用越来越广泛。对于建筑工地,开发一种高效、准确、安全的巡检技术,在工业和建筑现场,员工经常需要佩戴安全帽以防止头部受伤。安全帽识别技术可以帮助监测工作人员是否正确佩戴安全帽,以确保他们在危险环境中的安全。许多国家和地区都有法规和规范要求在特定环境中佩戴安全帽。安全帽识别技术有助于确保企业和个人遵守这些法规,降低事故风险。在大型工地或生产场所,实时监测员工是否佩戴安全帽对于管理人员来说是一项重要任务。安全帽识别系统可以自动执行这一任务,提高监控效率。机器人采用麦克拉姆轮,方便机器人能够实现多方位的平移,方便巡检识别工作的进行,以实现更加智能、高效的工作方式。在巡检识别方面,机器人可以通过搭载摄像头,实现对工作人员是否佩戴安全帽进行检测。
机器人巡检技术的发展,可以有效地提高工业和建筑领域的生产效率和质量,降低人工成本和安全风险。具体来说,机器人巡检可以代替人工进行工业设备和建筑物的巡检,提高巡检效率和准确性,降低人工巡检的安全风险。安全帽识别技术有助于预防意外事故,特别是那些可能导致头部受伤的事故。通过及时发现并纠正未佩戴安全帽的情况,可以降低事故发生的可能性。自动化的安全帽识别系统可以替代人工监测,提高工作效率。这对于大型工地或需要频繁监测的场所尤为重要。安全帽识别技术有助于确保企业和员工遵守安全规定,提高工作场所的合规性。此外,对于一些特定行业,未佩戴安全帽可能导致责任问题,因此及时的安全帽识别有助于规遍责任。通过防止事故的发生,安全帽识别技术可以帮助降低企业的人身伤害成本,包括医疗费用、赔偿金和法律费用。安全帽识别技术在提高工作场所安全性、遵守法规、降低事故风险以及提高管理效率方面具有重要意义。
作品简介
本项目利用视觉检测人是否佩戴安全帽,如果未佩戴安全帽将记录下来,上传到onenet云平台,通过TCP协议图传到电脑实时图像,装置利用麦克拉姆轮便于移动,控制通过esp_now协议控制,低延迟控制。本项目利用solidworks设计了二维云台结构连接上maixduino视觉模块,用户通过按红外遥控让红外遥控接收器接收到后,二维云台能够进行两个自由度的运动,让视觉处理器能够运动去检测安全帽。用户通过按红外遥控让红外遥控接收器接收到,控制小车的前进后退,当视觉处理器识别到是否佩戴安全帽会显示在lcd显示屏、电脑显示屏,当识别到佩戴安全帽后会上传到onenet云平台,本项目所有器件构成都来自得捷商城,以及全部应用到上面。
作品项目用到的板卡
ESP32-S3-DevKitC-1
ESP32-S3-DevKitC-1 是一款入门级开发板,搭载 Wi-Fi + Bluetooth® LE 模组 ESP32-S3-WROOM-1、ESP32-S3-WROOM-1U 或 ESP32-S3-WROOM-2。
参考链接:乐鑫ESP32-S3-DevKitC-1
ESP32-C3-LCDkit
ESP32-C3-LCDkit 是一款基于 ESP32-C3 芯片和 SPI 接口显示屏的评估开发板,不仅通过旋转编码器开关实现屏幕交互,还具有音频播放和红外无线控制功能。由于 ESP32-C3 具有成本低、功耗低、性能强的特点,能够满足用户基本的 GUI 交互需求,其在小尺寸屏幕的应用场景中占据优势。
参考链接:乐鑫ESP32-C3-LCDkit
MaixDuino 开发板
Maixduino开发板以M1Al模块作为核心单元,功能非常很强大,模块内置64位双核处理器芯片,拥有8M的片上SRAM,在Al机器视觉、听觉性能方便表现突出,内置多种硬件加速单元(KPU、FPU,FFT等),总算力最高可达1TOPS,可以方便地实现各类应用场景的机器视觉/听觉算法,也可以进行语音方向扫描和语音数据输出的前置处理工作。此外,开发板还配置了ESP32模块(WiFi+蓝牙一体),简单的操作即可轻松联网。
系统方案及功能实现
本项目是以esp32s3为主控制器,esp32c3为遥控装置,k210作为yolov2算法安全帽识别部署硬件,通过两个TB6612控制四路n20电机以及二维云台构成通过两个MG90s构成,系统框图如下图所示,其中esp32s3负责电机控制,舵机控制以及接收esp32c3的信号,两个esp32信息的传输通过低延迟、低功耗的esp-now协议。k210是负责视觉部分,通过数据集标注、在maixhub中训练模型得到最后的模型。esp32c3是自带红外接收,然后接收红外发射器做出相应的指令然后控制esp32s3主控制器。
小车硬件设计
使用立创eda进行设计,设计需要关注一下esp32s3的尺寸,然后设置好间距,方便打板子后,焊接排座直接插入到排座,然后使用的78m05将7.2转5v,以及使用ams117转3.3v来给esp32s3供电,为什么留出电阻口,是方便测试,电机驱动使用的是得捷商城购买的tb6612。
小车软件设计
小车的基本运动控制的话主要是提供四路pwm加上8个GPIO引脚控制正反转
例如控制pwm和限幅:
void Set_Pwm(int moto1, int moto2,int moto3,int moto4)
{
int Amplitude = 4000; //===PWM满幅是1024 限制在950
if (moto1 > 0)
{
digitalWrite(IN1_A, HIGH), digitalWrite(IN1_B, LOW); //TB6612的电平控制
}
else if(moto1 < 0)
{
digitalWrite(IN1_A, LOW), digitalWrite(IN1_B, HIGH); //TB6612的电平控制
}
else
{
digitalWrite(IN1_A, LOW), digitalWrite(IN1_B, LOW); //TB6612的电平控制
}
if (moto2 > 0)
{
digitalWrite(IN2_A, HIGH), digitalWrite(IN2_B, LOW); //TB6612的电平控制
}
else if(moto2 < 0)
{
digitalWrite(IN2_A, LOW), digitalWrite(IN2_B, HIGH); //TB6612的电平控制
}
else
{
digitalWrite(IN2_A, LOW), digitalWrite(IN2_B, LOW); //TB6612的电平控制
}
if (moto3 > 0)
{
digitalWrite(IN3_A, HIGH), digitalWrite(IN3_B, LOW); //TB6612的电平控制
}
else if(moto3 < 0)
{
digitalWrite(IN3_A, LOW), digitalWrite(IN3_B, HIGH); //TB6612的电平控制
}
else
{
digitalWrite(IN3_A, LOW), digitalWrite(IN3_B, LOW); //TB6612的电平控制
}
if (moto4 > 0)
{
digitalWrite(IN4_A, HIGH), digitalWrite(IN4_B, LOW); //TB6612的电平控制
}
else if(moto4 < 0)
{
digitalWrite(IN4_A, LOW), digitalWrite(IN4_B, HIGH); //TB6612的电平控制
}
else
{
digitalWrite(IN4_A, LOW), digitalWrite(IN4_B, LOW); //TB6612的电平控制
}
//功能:限制PWM赋值
if (moto1 < -Amplitude) moto1 = -Amplitude;
if (moto1 > Amplitude) moto1 = Amplitude;
if (moto2 < -Amplitude) moto2 = -Amplitude;
if (moto2 > Amplitude) moto2 = Amplitude;
if (moto3 < -Amplitude) moto3 = -Amplitude;
if (moto3 > Amplitude) moto3 = Amplitude;
if (moto4 < -Amplitude) moto4 = -Amplitude;
if (moto4 > Amplitude) moto4 = Amplitude;
//赋值给PWM寄存器
ledcWrite(pwm_Channel_1,abs(moto1));
ledcWrite(pwm_Channel_2,abs(moto2));
ledcWrite(pwm_Channel_3,abs(moto3));
ledcWrite(pwm_Channel_4,abs(moto4));
}
产生pwm:
void MOTOR_PWM_Init()
{
ledcSetup(pwm_Channel_1, freq, resolution); //PWM通道一开启设置
ledcAttachPin(PWM1, pwm_Channel_1); //PWM通道一和引脚PWMA关联
ledcWrite(pwm_Channel_1, 0); //PWM通道一占空比设置为零
ledcSetup(pwm_Channel_2, freq, resolution); //PWM通道二开启设置
ledcAttachPin(PWM2, pwm_Channel_2); //PWM通道二和引脚PWMB关联
ledcWrite(pwm_Channel_2, 0); //PWM通道二占空比设置为零
//
ledcSetup(pwm_Channel_3, freq, resolution); //PWM通道二开启设置
ledcAttachPin(PWM3, pwm_Channel_3); //PWM通道二和引脚PWMB关联
ledcWrite(pwm_Channel_3, 0); //PWM通道二占空比设置为零
ledcSetup(pwm_Channel_4, freq, resolution); //PWM通道二开启设置
ledcAttachPin(PWM4, pwm_Channel_4); //PWM通道二和引脚PWMB关联
ledcWrite(pwm_Channel_4, 0); //PWM通道二占空比设置为零
}
二维云台设计
软件使用的是solidworks,因为我是创维的3d打印机,所以使用的是创维的切片软件,在后面会提供stl文件。
材料清单:
铜柱
m2.5*10 3
m2.5*5 3
螺丝
m2.5*3 5
螺母
m2.5 5
两个舵机:mg90s(或者sg90)都行
安全帽识别实现
在 MaixHub 创建一个检测训练项目,然后采集数据并标注(可以在线标注),创建一个训练任务,参数选择你有的硬件平台,如果没有开发板可以使用手机,选择 yolov2 进行训练即可,训练后会得到模型文件以及曲线情况。
采集数据集可以用下面的代码,采集到的图像会保存到sd卡中,通过读卡器将图片导入maixhub在线标注即可:
import sensor, lcd
from Maix import GPIO
from fpioa_manager import fm
from board import board_info
import os, sys
import time
import image
#### image size ####
set_windowing = (224, 224)
#### sensor config ####
sensor.reset(freq=22000000, dual_buff=False)
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA) # 320x240
try:
sensor.set_jb_quality(95) # for IDE display quality
except Exception:
pass # no IDE support
if set_windowing:
sensor.set_windowing(set_windowing)
# sensor.set_auto_gain(False)
# sensor.set_auto_whitebal(False, rgb_gain_db=(0x52,0x40,0x4d))
# sensor.set_saturation(0)
# sensor.set_brightness(4)
# sensor.set_contrast(0)
# sensor.set_hmirror(True) # image horizonal mirror
# sensor.set_vflip(True) # image vertical flip
# sensor.set_auto_whitebal(False)
sensor.skip_frames()
#### lcd config ####
lcd.init(type=1, freq=15000000)
lcd.rotation(2)
#### boot key ####
boot_pin = 16 # board_info.BOOT_KEY
fm.register(boot_pin, fm.fpioa.GPIOHS0)
key = GPIO(GPIO.GPIOHS0, GPIO.PULL_UP)
######################################################
#### main ####
def capture_main(key):
def draw_string(img, x, y, text, color, scale, bg=None , full_w = False):
if bg:
if full_w:
full_w = img.width()
else:
full_w = len(text)*8*scale+4
img.draw_rectangle(x-2,y-2, full_w, 16*scale, fill=True, color=bg)
img = img.draw_string(x, y, text, color=color,scale=scale)
return img
def del_all_images():
os.chdir("/sd")
images_dir = "cap_images"
if images_dir in os.listdir():
os.chdir(images_dir)
types = os.listdir()
for t in types:
os.chdir(t)
files = os.listdir()
for f in files:
os.remove(f)
os.chdir("..")
os.rmdir(t)
os.chdir("..")
os.rmdir(images_dir)
# del_all_images()
os.chdir("/sd")
dirs = os.listdir()
images_dir = "cap_images"
last_dir = 0
for d in dirs:
if d.startswith(images_dir):
if len(d) > 11:
n = int(d[11:])
if n > last_dir:
last_dir = n
images_dir = "{}_{}".format(images_dir, last_dir+1)
print("save to ", images_dir)
if images_dir in os.listdir():
img = image.Image()
img = draw_string(img, 2, 200, "please del cap_images dir", color=lcd.WHITE,scale=1, bg=lcd.RED)
lcd.display(img)
sys.exit(1)
os.mkdir(images_dir)
last_cap_time = 0
last_btn_status = 1
save_dir = 0
save_count = 0
os.mkdir("{}/{}".format(images_dir, save_dir))
while(True):
img0 = sensor.snapshot()
if set_windowing:
img = image.Image()
img = img.draw_image(img0, (img.width() - set_windowing[0])//2, img.height() - set_windowing[1])
else:
img = img0.copy()
# img = img.resize(320, 240)
if key.value() == 0:
time.sleep_ms(30)
if key.value() == 0 and (last_btn_status == 1) and (time.ticks_ms() - last_cap_time > 500):
last_btn_status = 0
last_cap_time = time.ticks_ms()
else:
if time.ticks_ms() - last_cap_time > 5000:
img = draw_string(img, 2, 200, "release to change type", color=lcd.WHITE,scale=1, bg=lcd.RED)
else:
img = draw_string(img, 2, 200, "release to capture", color=lcd.WHITE,scale=1, bg=lcd.RED)
if time.ticks_ms() - last_cap_time > 2000:
img = draw_string(img, 2, 160, "keep push to change type", color=lcd.WHITE,scale=1, bg=lcd.RED)
else:
time.sleep_ms(30)
if key.value() == 1 and (last_btn_status == 0):
if time.ticks_ms() - last_cap_time > 5000:
img = draw_string(img, 2, 200, "change object type", color=lcd.WHITE,scale=1, bg=lcd.RED)
lcd.display(img)
time.sleep_ms(1000)
save_dir += 1
save_count = 0
dir_name = "{}/{}".format(images_dir, save_dir)
os.mkdir(dir_name)
else:
draw_string(img, 2, 200, "capture image {}".format(save_count), color=lcd.WHITE,scale=1, bg=lcd.RED)
lcd.display(img)
f_name = "{}/{}/{}.jpg".format(images_dir, save_dir, save_count)
img0.save(f_name, quality=95)
save_count += 1
last_btn_status = 1
img = draw_string(img, 2, 0, "will save to {}/{}/{}.jpg".format(images_dir, save_dir, save_count), color=lcd.WHITE,scale=1, bg=lcd.RED, full_w=True)
lcd.display(img)
del img
del img0
def main():
try:
capture_main(key)
except Exception as e:
print("error:", e)
import uio
s = uio.StringIO()
sys.print_exception(e, s)
s = s.getvalue()
img = image.Image()
img.draw_string(0, 0, s)
lcd.display(img)
main()
上传图片到onenet
上传图片到onenet可以通过http的方式进行上传到onenet。
例子如下:
url = "https://iot-api.heclouds.com/device/file-upload"
payload = {'device_name': '',
'product_id': ''}
files=[
('file',('logo1.jpg',open('tmp.jpg','rb'),'你的类型))
]
headers = {
'Authorization': ''
}
response = requests.request("POST", url, headers=headers, data=payload, files=files)
print(response.text)
项目源码
安全帽模型下载链接如下:http://download.eeworld.com.cn/detail/wuboy/630433
esp32红外接收端下载链接如下:http://download.eeworld.com.cn/detail/wuboy/630432
小车底板下载链接如下:http://download.eeworld.com.cn/detail/wuboy/630431
esp32控制端下载链接如下:http://download.eeworld.com.cn/detail/wuboy/630430
作品功能演示视频
项目总结
整个项目将得捷购买的材料全部使用上了,锻炼了自己换板子,以及调试能力,
最后实现了功能,本项目利用视觉检测人是否佩戴安全帽,如果未佩戴安全帽将记录下来,上传到onenet云平台,通过TCP协议图传到电脑实时图像,装置利用麦克拉姆轮便于移动,控制通过esp_now协议控制,低延迟控制。最后十分感谢得捷官方,得捷的工作人员。
帖子分享:http://bbs.eeworld.com.cn/thread-1266467-1-1.html
帖子分享:http://bbs.eeworld.com.cn/thread-1266054-1-1.html