云天 发表于 2024-1-22 20:19:40

行空板推流B站直播 弹幕控制舵机摆动 浇花

本帖最后由 云天 于 2024-1-22 20:19 编辑

行空直播 弹幕物控
【项目背景】
       本项目想实现从万物互联到万物可视。通过实景智能直播将智能技术与直播相结合实现新型直播方式,通过实时采集、编辑和传输实景数据,实现更加真实、生动的直播效果。并可通过弹幕留言来实现远程控制浇水、喂食等功能。【项目设计】
       平时,会全家出远门,一走好几天。家里的花和猫都处于无人照顾的情况。有时会给花一次性浇很多水,给猫放很多的猫粮和水。花还好,就是猫,每次回来都会胖很多。
       想通过网络查看家里的情况,并能通过远程控制的方式,给花浇水、给猫喂食。远程控制可以使用物联网,查看图像可使用网络摄像头。那怎么将两者结合,我想到了直播。
【项目方案】
       1.使用B站直播,获取服务器地址和直播码。2.使用opencv库获取摄像头图像,使用FFmpeg进程,将视频数据通过管道传递给RTMP推流B站,进行直播。
       3.通过Pinpong库获取温湿度传感器、土壤湿度传感器数值,并通过“ImageDraw”库将中文及传感器数值绘制在画面上。
       4.使用浏览器“开发者工具”,获取cookies和headers。
       5.通过requests库的get方法,获取直播弹幕留言,并通过pinpong库控制舵机及电磁继电器。
【硬件装置】
       行空板加扩展板,温湿度传感器接P1引脚,土壤湿度传感器接P4引脚,光照传感器接P10引脚。两舵机分别引脚P8、P9。电磁继电器和蓝光LED分别接P20、P19引脚。

       土壤湿度传感器插入花盆土壤中。

       水泵出水口有夹子固定到花盆里。

       水泵电源接电磁继电器

       摄像头接行空板USB口,并固定在直播架上。





【获取直播推流码】



【直播推流】
行空板自带了ffmpeg库,可直接使用。
import cv2

import subprocess

# 设置摄像头参数
capture = cv2.VideoCapture(0)
capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# RTMP推流地址
url = 'rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_511218715_31018533&key=*****************&schedule=rtmp&pflag=1'

# 启动FFmpeg进程,将视频数据通过管道传递给RTMP推流
cmd = ['ffmpeg', '-y', '-f', 'rawvideo', '-pix_fmt', 'bgr24', '-s', '640x480', '-i', '-', '-c:v', 'libx264', '-pix_fmt', \
   'yuv420p', '-preset', 'ultrafast', '-f', 'flv', url]
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)

# 循环读取摄像头数据,将数据写入管道中
while True:
    ret, frame = capture.read()
    if not ret:
      break

    p.stdin.write(frame.tostring())

# 关闭进程和摄像头
p.communicate()
p.stdin.close()
capture.release()

【实时数据显示】
通过Pinpong库获取温湿度传感器、土壤湿度传感器数值,并通过“ImageDraw”库将中文及传感器数值绘制在画面上。


import cv2

import subprocess
from PIL import ImageFont,ImageDraw,Image
import numpy as np
from pinpong.board import DHT11
from pinpong.board import Board
from pinpong.board import Pin


Board().begin()
pin1 = Pin(Pin.P1)
dht1 = DHT11(pin1)
pin0 = Pin(Pin.P4, Pin.ANALOG)
pin2 = Pin(Pin.P2, Pin.ANALOG)
# 设置摄像头参数
capture = cv2.VideoCapture(0)
capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# RTMP推流地址
url = 'rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_511218715_31018533&key=*********************&schedule=rtmp&pflag=1'

# 启动FFmpeg进程,将视频数据通过管道传递给RTMP推流
cmd = ['ffmpeg', '-y', '-f', 'rawvideo', '-pix_fmt', 'bgr24', '-s', '640x480', '-i', '-', '-c:v', 'libx264', '-pix_fmt', \
'yuv420p', '-preset', 'ultrafast', '-f', 'flv', url]
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)

# 循环读取摄像头数据,将数据写入管道中
while True:
ret, frame = capture.read()
if not ret:
      break
#cv2.putText(frame, "hello", (100, 100), cv2.FONT_HERSHEY_COMPLEX, 1,(255,0,0),1)
frame=Image.fromarray(frame)
font1=ImageFont.truetype("./msyh.ttc",50)
draw=ImageDraw.Draw(frame)
draw.text((10,10),"温度:"+str(dht1.temp_c())+"湿度:"+str(dht1.humidity()),font=font1,fill=(0,0,255))
draw.text((10,400),"光照:"+str(pin2.read_analog())+"土湿度:"+str(pin0.read_analog()),font=font1,fill=(0,0,255))
frame=np.array(frame)
p.stdin.write(frame.tostring())

# 关闭进程和摄像头
p.communicate()
p.stdin.close()
capture.release()

【获取直播信息】

       使用浏览器“开发者工具”,获取cookies和headers。
       1.复制信息

       2.使用Convert curl commands to Python (curlconverter.com)网站工具,将信息转换为python可用数据。

(cookies信息有效期为7天)

【弹幕控制】
      通过requests库的get方法,获取直播弹幕留言。

import requests
import time
import random
import json


def send_Danmu():
    watertime=""
    liketime=""
    watertimetem=""
    liketimetem=""
    while True:

       cookies = {**************}

       headers = {**************}

      response = requests.get('https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory?roomid=23994618&room_type=0', cookies=cookies, headers=headers)
      json_data=response.text
      
      data=json.loads(json_data)
      if data["code"]==0:
             texts=data["data"]["room"]
             for text in texts :
               if text["nickname"]=="创客云天":
                   if text["text"]=="浇水":
                     if text["timeline"]!=watertimetem:
                           watertimetem=text["timeline"]
                           
               if text["text"]=="[牛]":
                     if text["timeline"]!=liketimetem:
                         liketimetem= text["timeline"]
                        
             if watertimetem!=watertime:
                watertime=watertimetem
                print("浇水")
             if liketimetem!=liketime:
                liketime=liketimetem
                print("[牛]")
      time. sleep(21)#冷却时间,可以自己调
send_Danmu()
       并通过pinpong库控制舵机及电磁继电器。
from pinpong.board import Board
from pinpong.board import Pin
import requests
import time
import random
import json
Board().begin()
pin20 = Pin(Pin.P20, Pin.OUT)
pin19 = Pin(Pin.P19, Pin.OUT)
def send_Danmu():

    watertime=""
    liketime=""
    watertimetem=""
    liketimetem=""
    bs=0
    timekg=time.time()
    timefw=time.time()
    while True:
      if time.time()-timefw>5:
      timefw=time.time()
      cookies = {**************}

      headers = {**************}

      response = requests.get('https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory?roomid=23994618&room_type=0', cookies=cookies, headers=headers)
      json_data=response.text
      
      data=json.loads(json_data)
      if data["code"]==0:
             texts=data["data"]["room"]
             for text in texts :
               if text["nickname"]=="创客云天":
                   if text["text"]=="浇水":
                     if text["timeline"]!=watertimetem:
                           watertimetem=text["timeline"]
                           
               if text["text"]=="[牛]":
                     if text["timeline"]!=liketimetem:
                         liketimetem= text["timeline"]
                        
             if watertimetem!=watertime:
               if bs==0:
                   watertime=watertimetem
                   pin20.value(1)
                   pin19.value(1)               
                   timekg=time.time()
                   bs=1
                   print("开始浇水 ")
             if liketimetem!=liketime:
                liketime=liketimetem
                print("[牛]")
      if time.time()-timekg>3:
         if bs==1:
             timekg=time.time()
             pin20.value(0)
             pin19.value(0)
             bs=0
             print("停止浇水 ")      
      
send_Danmu()
       增加控制舵机功能
from pinpong.board import Board,Servo
from pinpong.board import Pin
import requests
import time
import random
import json
Board().begin()
pin20 = Pin(Pin.P20, Pin.OUT)
pin19 = Pin(Pin.P19, Pin.OUT)
pin20.value(0)
pin19.value(0)
s1 = Servo(Pin(Pin.P8))
s2 = Servo(Pin(Pin.P9))
def send_Danmu():

    watertime=""
    liketime=""
    watertimetem=""
    liketimetem=""
    bs=0
    bs2=0
    timekg=time.time()
    timefw=time.time()
    timedj=time.time()
    while True:
      if time.time()-timefw>5:
      timefw=time.time()
      cookies = {******************}

      headers = {******************}

      response = requests.get('https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory?roomid=23994618&room_type=0', cookies=cookies, headers=headers)
      json_data=response.text
      
      data=json.loads(json_data)
      if data["code"]==0:
             texts=data["data"]["room"]
             for text in texts :
               if text["nickname"]=="创客云天":
                   if text["text"]=="浇水":
                     if text["timeline"]!=watertimetem:
                           watertimetem=text["timeline"]
                           
               if text["text"]=="[牛]":
                     if text["timeline"]!=liketimetem:
                         liketimetem= text["timeline"]
                        
             if watertimetem!=watertime:
               if bs==0:
                   watertime=watertimetem
                   pin20.value(1)
                   pin19.value(1)               
                   timekg=time.time()
                   bs=1
                   print("开始浇水 ")
             if liketimetem!=liketime:
                liketime=liketimetem
                s1.angle(60) #控制舵机转到0度位置
                s2.angle(60) #控制舵机转到0度位置
                timedj=time.time()
                bs2=1
                print("开始摆动")
      if time.time()-timekg>3:
         if bs==1:
             timekg=time.time()
             pin20.value(0)
             pin19.value(0)
             bs=0
             print("停止浇水 ")
      if time.time()-timedj>3:
         if bs2==1:
             timedj=time.time()
             s1.angle(120) #控制舵机转到0度位置
             s2.angle(120) #控制舵机转到0度位置
             bs2=0
             print("停止摆动")            
      
send_Danmu()
【完整代码】
将直播与弹幕控制程序结合
import cv2

import subprocess
from PIL import ImageFont,ImageDraw,Image
import numpy as np
from pinpong.board import DHT11
from pinpong.board import Board,Servo
from pinpong.board import Pin
import requests
import time
import random
import json
from unihiker import GUI
u_gui=GUI()
显示1=u_gui.draw_text(text="行空板",x=30,y=10,font_size=40, color="#0000FF")
显示2=u_gui.draw_text(text="直播控制",x=10,y=80,font_size=40, color="#FF0000")
显示3=u_gui.draw_text(text="",x=10,y=180,font_size=40, color="#00FF00")

Board().begin()
pin20 = Pin(Pin.P20, Pin.OUT)
pin19 = Pin(Pin.P19, Pin.OUT)
pin20.value(0)
pin19.value(0)
s1 = Servo(Pin(Pin.P8))
s2 = Servo(Pin(Pin.P9))
pin1 = Pin(Pin.P1)
dht1 = DHT11(pin1)
pin4 = Pin(Pin.P4, Pin.ANALOG)
pin10 = Pin(Pin.P10, Pin.ANALOG)

watertime=""
liketime=""
watertimetem=""
liketimetem=""
bs=0
bs2=0
timekg=time.time()
timefw=time.time()
timedj=time.time()

# 设置摄像头参数
capture = cv2.VideoCapture(0)
capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

# RTMP推流地址
url = 'rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_511218715_31018533&key=**************************&schedule=rtmp&pflag=1'

# 启动FFmpeg进程,将视频数据通过管道传递给RTMP推流
cmd = ['ffmpeg', '-y', '-f', 'rawvideo', '-pix_fmt', 'bgr24', '-s', '640x480', '-i', '-', '-c:v', 'libx264', '-pix_fmt', \
   'yuv420p', '-preset', 'ultrafast', '-f', 'flv', url]
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)

# 循环读取摄像头数据,将数据写入管道中
while True:
   ret, frame = capture.read()
   if not ret:
       break
   #cv2.putText(frame, "hello", (100, 100), cv2.FONT_HERSHEY_COMPLEX, 1,(255,0,0),1)
   frame=Image.fromarray(frame)
   font1=ImageFont.truetype("./msyh.ttc",50)
   draw=ImageDraw.Draw(frame)
   draw.text((10,10),"温度:"+str(dht1.temp_c())+"湿度:"+str(dht1.humidity()),font=font1,fill=(0,0,255))
   draw.text((10,400),"光照:"+str(pin10.read_analog())+"土湿度:"+str(pin4.read_analog()),font=font1,fill=(0,0,255))
   frame=np.array(frame)
   p.stdin.write(frame.tostring())
   if time.time()-timefw>5:
      timefw=time.time()
      cookies = {***********************************}

      headers = {***********************************}

      response = requests.get('https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory?roomid=23994618&room_type=0', cookies=cookies, headers=headers)
      json_data=response.text
      
      data=json.loads(json_data)
      if data["code"]==0:
             texts=data["data"]["room"]
             for text in texts :
               if text["nickname"]=="创客云天":
                   if text["text"]=="浇水":
                     if text["timeline"]!=watertimetem:
                           watertimetem=text["timeline"]
                           显示3.config(text=text["nickname"])
               if text["text"]=="[牛]":
                     if text["timeline"]!=liketimetem:
                         liketimetem= text["timeline"]
                         显示3.config(text=text["nickname"])
                        
             if watertimetem!=watertime:
               if bs==0:
                   watertime=watertimetem
                   pin20.value(1)
                   pin19.value(1)               
                   timekg=time.time()
                   bs=1
                   print("开始浇水 ")
             if liketimetem!=liketime:
                liketime=liketimetem
                s1.angle(60) #控制舵机转到0度位置
                s2.angle(120) #控制舵机转到0度位置
                pin20.value(1)
                timedj=time.time()
                bs2=1
                print("开始摆动")
   if time.time()-timekg>3:
         if bs==1:
             timekg=time.time()
             pin20.value(0)
             pin19.value(0)
             bs=0
             print("停止浇水 ")
   if time.time()-timedj>3:
         if bs2==1:
             timedj=time.time()
             s1.angle(120) #控制舵机转到0度位置
             s2.angle(60) #控制舵机转到0度位置
             pin20.value(0)
             bs2=0
             print("停止摆动")
# 关闭进程和摄像头
p.communicate()
p.stdin.close()
capture.release()





【演示视频】
https://www.bilibili.com/video/BV1uT4y1b7hY/?share_source=copy_web&vd_source=98855d5b99ff76982639c5ca6ff6f528




hnyzcj 发表于 2024-1-23 07:47:30

666666

RRoy 发表于 2024-1-23 16:23:19

老师,这个假如观众发弹幕的话也能操控吗

云天 发表于 2024-1-23 23:19:26

RRoy 发表于 2024-1-23 16:23
老师,这个假如观众发弹幕的话也能操控吗

可以,好几个人已经测试过了

RRoy 发表于 2024-1-24 10:36:10

云天 发表于 2024-1-23 23:19
可以,好几个人已经测试过了

那遇到捣乱分子,植物就不好受了{:7_224:}

云天 发表于 2024-1-25 15:39:52

“那遇到捣乱分子,植物就不好受了”
捣乱分子,只能控制舵机摆动,浇水只有我自己发信息才可以。

木子呢 发表于 2024-1-26 10:42:18

RRoy 发表于 2024-1-23 16:23
老师,这个假如观众发弹幕的话也能操控吗

我亲测过大神的这个项目,嘿嘿
页: [1]
查看完整版本: 行空板推流B站直播 弹幕控制舵机摆动 浇花