5093浏览
查看: 5093|回复: 6

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

[复制链接]
本帖最后由 云天 于 2024-1-22 20:19 编辑

行空直播 弹幕物控

【项目背景】
       本项目想实现从万物互联到万物可视。通过实景智能直播将智能技术与直播相结合实现新型直播方式,通过实时采集、编辑和传输实景数据,实现更加真实、生动的直播效果。并可通过弹幕留言来实现远程控制浇水、喂食等功能。
【项目设计】
       平时,会全家出远门,一走好几天。家里的花和猫都处于无人照顾的情况。有时会给花一次性浇很多水,给猫放很多的猫粮和水。花还好,就是猫,每次回来都会胖很多。
       想通过网络查看家里的情况,并能通过远程控制的方式,给花浇水、给猫喂食。远程控制可以使用物联网,查看图像可使用网络摄像头。那怎么将两者结合,我想到了直播。
行空板推流B站直播 弹幕控制舵机摆动 浇花图1

【项目方案】
       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引脚。
行空板推流B站直播 弹幕控制舵机摆动 浇花图7

       土壤湿度传感器插入花盆土壤中。
行空板推流B站直播 弹幕控制舵机摆动 浇花图4

       水泵出水口有夹子固定到花盆里。
行空板推流B站直播 弹幕控制舵机摆动 浇花图9

       水泵电源接电磁继电器
行空板推流B站直播 弹幕控制舵机摆动 浇花图8

       摄像头接行空板USB口,并固定在直播架上。
行空板推流B站直播 弹幕控制舵机摆动 浇花图2


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


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

【获取直播推流码】

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


【直播推流】
行空板自带了ffmpeg库,可直接使用。
  1. import cv2
  2. import subprocess
  3. # 设置摄像头参数
  4. capture = cv2.VideoCapture(0)
  5. capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
  6. capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
  7. # RTMP推流地址
  8. url = 'rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_511218715_31018533&key=*****************&schedule=rtmp&pflag=1'
  9. # 启动FFmpeg进程,将视频数据通过管道传递给RTMP推流
  10. cmd = ['ffmpeg', '-y', '-f', 'rawvideo', '-pix_fmt', 'bgr24', '-s', '640x480', '-i', '-', '-c:v', 'libx264', '-pix_fmt', \
  11.    'yuv420p', '-preset', 'ultrafast', '-f', 'flv', url]
  12. p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
  13. # 循环读取摄像头数据,将数据写入管道中
  14. while True:
  15.     ret, frame = capture.read()
  16.     if not ret:
  17.       break
  18.     p.stdin.write(frame.tostring())
  19. # 关闭进程和摄像头
  20. p.communicate()
  21. p.stdin.close()
  22. capture.release()
复制代码
行空板推流B站直播 弹幕控制舵机摆动 浇花图14


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

  1. import cv2
  2. import subprocess
  3. from PIL import ImageFont,ImageDraw,Image
  4. import numpy as np
  5. from pinpong.board import DHT11
  6. from pinpong.board import Board
  7. from pinpong.board import Pin
  8. Board().begin()
  9. pin1 = Pin(Pin.P1)
  10. dht1 = DHT11(pin1)
  11. pin0 = Pin(Pin.P4, Pin.ANALOG)
  12. pin2 = Pin(Pin.P2, Pin.ANALOG)
  13. # 设置摄像头参数
  14. capture = cv2.VideoCapture(0)
  15. capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
  16. capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
  17. # RTMP推流地址
  18. url = 'rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_511218715_31018533&key=*********************&schedule=rtmp&pflag=1'
  19. # 启动FFmpeg进程,将视频数据通过管道传递给RTMP推流
  20. cmd = ['ffmpeg', '-y', '-f', 'rawvideo', '-pix_fmt', 'bgr24', '-s', '640x480', '-i', '-', '-c:v', 'libx264', '-pix_fmt', \
  21.   'yuv420p', '-preset', 'ultrafast', '-f', 'flv', url]
  22. p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
  23. # 循环读取摄像头数据,将数据写入管道中
  24. while True:
  25.   ret, frame = capture.read()
  26.   if not ret:
  27.       break
  28.   #cv2.putText(frame, "hello", (100, 100), cv2.FONT_HERSHEY_COMPLEX, 1,(255,0,0),1)
  29.   frame=Image.fromarray(frame)
  30.   font1=ImageFont.truetype("./msyh.ttc",50)
  31.   draw=ImageDraw.Draw(frame)
  32.   draw.text((10,10),"温度:"+str(dht1.temp_c())+"  湿度:"+str(dht1.humidity()),font=font1,fill=(0,0,255))
  33.   draw.text((10,400),"光照:"+str(pin2.read_analog())+"  土湿度:"+str(pin0.read_analog()),font=font1,fill=(0,0,255))
  34.   frame=np.array(frame)
  35.   p.stdin.write(frame.tostring())
  36. # 关闭进程和摄像头
  37. p.communicate()
  38. p.stdin.close()
  39. capture.release()
复制代码

【获取直播信息】

       使用浏览器“开发者工具”,获取cookies和headers。
       1.复制信息
行空板推流B站直播 弹幕控制舵机摆动 浇花图12

       2.使用Convert curl commands to Python (curlconverter.com)网站工具,将信息转换为python可用数据。
行空板推流B站直播 弹幕控制舵机摆动 浇花图13

(cookies信息有效期为7天)


【弹幕控制】
        通过requests库的get方法,获取直播弹幕留言。
  1. import requests
  2. import time
  3. import random
  4. import json
  5. def send_Danmu():
  6.     watertime=""
  7.     liketime=""
  8.     watertimetem=""
  9.     liketimetem=""
  10.     while True:
  11.        cookies = {**************}
  12.        headers = {**************}
  13.         response = requests.get('https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory?roomid=23994618&room_type=0', cookies=cookies, headers=headers)
  14.         json_data=response.text
  15.         
  16.         data=json.loads(json_data)
  17.         if data["code"]==0:
  18.              texts=data["data"]["room"]
  19.              for text in texts :
  20.                  if text["nickname"]=="创客云天":
  21.                    if text["text"]=="浇水":
  22.                        if text["timeline"]!=watertimetem:
  23.                            watertimetem=text["timeline"]
  24.                            
  25.                  if text["text"]=="[牛]":
  26.                      if text["timeline"]!=liketimetem:
  27.                          liketimetem= text["timeline"]
  28.                         
  29.              if watertimetem!=watertime:
  30.                 watertime=watertimetem
  31.                 print("浇水")
  32.              if liketimetem!=liketime:
  33.                 liketime=liketimetem
  34.                 print("[牛]")
  35.         time. sleep(21)#冷却时间,可以自己调
  36. send_Danmu()
复制代码
      并通过pinpong库控制舵机及电磁继电器。
  1. from pinpong.board import Board
  2. from pinpong.board import Pin
  3. import requests
  4. import time
  5. import random
  6. import json
  7. Board().begin()
  8. pin20 = Pin(Pin.P20, Pin.OUT)
  9. pin19 = Pin(Pin.P19, Pin.OUT)
  10. def send_Danmu():
  11.     watertime=""
  12.     liketime=""
  13.     watertimetem=""
  14.     liketimetem=""
  15.     bs=0
  16.     timekg=time.time()
  17.     timefw=time.time()
  18.     while True:
  19.       if time.time()-timefw>5:
  20.         timefw=time.time()
  21.         cookies = {**************}
  22.         headers = {**************}
  23.         response = requests.get('https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory?roomid=23994618&room_type=0', cookies=cookies, headers=headers)
  24.         json_data=response.text
  25.         
  26.         data=json.loads(json_data)
  27.         if data["code"]==0:
  28.              texts=data["data"]["room"]
  29.              for text in texts :
  30.                  if text["nickname"]=="创客云天":
  31.                    if text["text"]=="浇水":
  32.                        if text["timeline"]!=watertimetem:
  33.                            watertimetem=text["timeline"]
  34.                            
  35.                  if text["text"]=="[牛]":
  36.                      if text["timeline"]!=liketimetem:
  37.                          liketimetem= text["timeline"]
  38.                         
  39.              if watertimetem!=watertime:
  40.                  if bs==0:
  41.                    watertime=watertimetem
  42.                    pin20.value(1)
  43.                    pin19.value(1)               
  44.                    timekg=time.time()
  45.                    bs=1
  46.                    print("开始浇水 ")
  47.              if liketimetem!=liketime:
  48.                 liketime=liketimetem
  49.                 print("[牛]")
  50.       if time.time()-timekg>3:
  51.            if bs==1:
  52.              timekg=time.time()  
  53.              pin20.value(0)
  54.              pin19.value(0)
  55.              bs=0
  56.              print("停止浇水 ")      
  57.       
  58. send_Danmu()
复制代码
      增加控制舵机功能
  1. from pinpong.board import Board,Servo
  2. from pinpong.board import Pin
  3. import requests
  4. import time
  5. import random
  6. import json
  7. Board().begin()
  8. pin20 = Pin(Pin.P20, Pin.OUT)
  9. pin19 = Pin(Pin.P19, Pin.OUT)
  10. pin20.value(0)
  11. pin19.value(0)
  12. s1 = Servo(Pin(Pin.P8))
  13. s2 = Servo(Pin(Pin.P9))
  14. def send_Danmu():
  15.     watertime=""
  16.     liketime=""
  17.     watertimetem=""
  18.     liketimetem=""
  19.     bs=0
  20.     bs2=0
  21.     timekg=time.time()
  22.     timefw=time.time()
  23.     timedj=time.time()
  24.     while True:
  25.       if time.time()-timefw>5:
  26.         timefw=time.time()
  27.         cookies = {******************}
  28.         headers = {******************}
  29.         response = requests.get('https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory?roomid=23994618&room_type=0', cookies=cookies, headers=headers)
  30.         json_data=response.text
  31.         
  32.         data=json.loads(json_data)
  33.         if data["code"]==0:
  34.              texts=data["data"]["room"]
  35.              for text in texts :
  36.                  if text["nickname"]=="创客云天":
  37.                    if text["text"]=="浇水":
  38.                        if text["timeline"]!=watertimetem:
  39.                            watertimetem=text["timeline"]
  40.                            
  41.                  if text["text"]=="[牛]":
  42.                      if text["timeline"]!=liketimetem:
  43.                          liketimetem= text["timeline"]
  44.                         
  45.              if watertimetem!=watertime:
  46.                  if bs==0:
  47.                    watertime=watertimetem
  48.                    pin20.value(1)
  49.                    pin19.value(1)               
  50.                    timekg=time.time()
  51.                    bs=1
  52.                    print("开始浇水 ")
  53.              if liketimetem!=liketime:
  54.                 liketime=liketimetem
  55.                 s1.angle(60) #控制舵机转到0度位置
  56.                 s2.angle(60) #控制舵机转到0度位置
  57.                 timedj=time.time()
  58.                 bs2=1
  59.                 print("开始摆动")
  60.       if time.time()-timekg>3:
  61.            if bs==1:
  62.              timekg=time.time()  
  63.              pin20.value(0)
  64.              pin19.value(0)
  65.              bs=0
  66.              print("停止浇水 ")
  67.       if time.time()-timedj>3:
  68.            if bs2==1:
  69.              timedj=time.time()  
  70.              s1.angle(120) #控制舵机转到0度位置
  71.              s2.angle(120) #控制舵机转到0度位置
  72.              bs2=0
  73.              print("停止摆动")              
  74.       
  75. send_Danmu()
复制代码
【完整代码】
将直播与弹幕控制程序结合
  1. import cv2
  2. import subprocess
  3. from PIL import ImageFont,ImageDraw,Image
  4. import numpy as np
  5. from pinpong.board import DHT11
  6. from pinpong.board import Board,Servo
  7. from pinpong.board import Pin
  8. import requests
  9. import time
  10. import random
  11. import json
  12. from unihiker import GUI
  13. u_gui=GUI()
  14. 显示1=u_gui.draw_text(text="行空板",x=30,y=10,font_size=40, color="#0000FF")
  15. 显示2=u_gui.draw_text(text="直播控制",x=10,y=80,font_size=40, color="#FF0000")
  16. 显示3=u_gui.draw_text(text="",x=10,y=180,font_size=40, color="#00FF00")
  17. Board().begin()
  18. pin20 = Pin(Pin.P20, Pin.OUT)
  19. pin19 = Pin(Pin.P19, Pin.OUT)
  20. pin20.value(0)
  21. pin19.value(0)
  22. s1 = Servo(Pin(Pin.P8))
  23. s2 = Servo(Pin(Pin.P9))
  24. pin1 = Pin(Pin.P1)
  25. dht1 = DHT11(pin1)
  26. pin4 = Pin(Pin.P4, Pin.ANALOG)
  27. pin10 = Pin(Pin.P10, Pin.ANALOG)
  28. watertime=""
  29. liketime=""
  30. watertimetem=""
  31. liketimetem=""
  32. bs=0
  33. bs2=0
  34. timekg=time.time()
  35. timefw=time.time()
  36. timedj=time.time()
  37. # 设置摄像头参数
  38. capture = cv2.VideoCapture(0)
  39. capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
  40. capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
  41. # RTMP推流地址
  42. url = 'rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_511218715_31018533&key=**************************&schedule=rtmp&pflag=1'
  43. # 启动FFmpeg进程,将视频数据通过管道传递给RTMP推流
  44. cmd = ['ffmpeg', '-y', '-f', 'rawvideo', '-pix_fmt', 'bgr24', '-s', '640x480', '-i', '-', '-c:v', 'libx264', '-pix_fmt', \
  45.    'yuv420p', '-preset', 'ultrafast', '-f', 'flv', url]
  46. p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
  47. # 循环读取摄像头数据,将数据写入管道中
  48. while True:
  49.    ret, frame = capture.read()
  50.    if not ret:
  51.        break
  52.    #cv2.putText(frame, "hello", (100, 100), cv2.FONT_HERSHEY_COMPLEX, 1,(255,0,0),1)
  53.    frame=Image.fromarray(frame)
  54.    font1=ImageFont.truetype("./msyh.ttc",50)
  55.    draw=ImageDraw.Draw(frame)
  56.    draw.text((10,10),"温度:"+str(dht1.temp_c())+"  湿度:"+str(dht1.humidity()),font=font1,fill=(0,0,255))
  57.    draw.text((10,400),"光照:"+str(pin10.read_analog())+"  土湿度:"+str(pin4.read_analog()),font=font1,fill=(0,0,255))
  58.    frame=np.array(frame)
  59.    p.stdin.write(frame.tostring())
  60.    if time.time()-timefw>5:
  61.         timefw=time.time()
  62.         cookies = {***********************************}
  63.         headers = {***********************************}
  64.         response = requests.get('https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory?roomid=23994618&room_type=0', cookies=cookies, headers=headers)
  65.         json_data=response.text
  66.         
  67.         data=json.loads(json_data)
  68.         if data["code"]==0:
  69.              texts=data["data"]["room"]
  70.              for text in texts :
  71.                  if text["nickname"]=="创客云天":
  72.                    if text["text"]=="浇水":
  73.                        if text["timeline"]!=watertimetem:
  74.                            watertimetem=text["timeline"]
  75.                            显示3.config(text=text["nickname"])
  76.                  if text["text"]=="[牛]":
  77.                      if text["timeline"]!=liketimetem:
  78.                          liketimetem= text["timeline"]
  79.                          显示3.config(text=text["nickname"])
  80.                         
  81.              if watertimetem!=watertime:
  82.                  if bs==0:
  83.                    watertime=watertimetem
  84.                    pin20.value(1)
  85.                    pin19.value(1)               
  86.                    timekg=time.time()
  87.                    bs=1
  88.                    print("开始浇水 ")
  89.              if liketimetem!=liketime:
  90.                 liketime=liketimetem
  91.                 s1.angle(60) #控制舵机转到0度位置
  92.                 s2.angle(120) #控制舵机转到0度位置
  93.                 pin20.value(1)
  94.                 timedj=time.time()
  95.                 bs2=1
  96.                 print("开始摆动")
  97.    if time.time()-timekg>3:
  98.            if bs==1:
  99.              timekg=time.time()  
  100.              pin20.value(0)
  101.              pin19.value(0)
  102.              bs=0
  103.              print("停止浇水 ")
  104.    if time.time()-timedj>3:
  105.            if bs2==1:
  106.              timedj=time.time()  
  107.              s1.angle(120) #控制舵机转到0度位置
  108.              s2.angle(60) #控制舵机转到0度位置
  109.              pin20.value(0)
  110.              bs2=0
  111.              print("停止摆动")  
  112. # 关闭进程和摄像头
  113. p.communicate()
  114. p.stdin.close()
  115. capture.release()
复制代码

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


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


【演示视频】






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
可以,好几个人已经测试过了

那遇到捣乱分子,植物就不好受了
回复

使用道具 举报

云天  初级技神
 楼主|

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

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

使用道具 举报

木子呢  管理员

发表于 2024-1-26 10:42:18

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

我亲测过大神的这个项目,嘿嘿
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail