找回密码
 立即注册
首页 业界区 安全 与狼共舞——为Go2安装M416全自动水弹枪(二) ...

与狼共舞——为Go2安装M416全自动水弹枪(二)

睁扼妤 4 天前
导语

  作为本系列的开篇,有必要先做些约定:

  • 以后的内容仅提供核心功能的代码,尽可能简洁,毕竟每个狗主都会有自己的想法,会添加自己的功能,写太多不容易整合,更何况我也没做什么复杂功能。
  • 提供的代码片段不进行过多解释,程序语言也是语言,“领会精神“”就好。
  • 不管是硬件设计还是软件编程部分,咱遵循三哥军工的设计思路,能依赖现有软件功能的就绝不自己编码,能购买的电子模块绝不自己动手制作。
  • 机器人操作系统采用Ros2 Foxy,软件编程使用python语言,硬件编程c语言,操作系统Ubuntu 20.04。
     
 
功能

  这里的功能仅指与架枪相关的功能。(水弹枪是儿子友情赞助的,请勿对人射击。)

  • 通过3D打印机打印支架和电器盒子,固定枪和电路板。
  • 由go2的扩展坞发送UDP广播消息给控制电路,击发开火。
  • 编程实现原厂遥控器的向上按钮作为开火键。
  • 用cv2实现一个简单的人脸识别系统。
  • 实现一个deepseek agent功能,让go2能理解你发出的指令,并按照你的指令执行任务(如,找到张三,立即开火。 或者 打个招呼 ...)
1.jpeg

 
硬件

  先上图,实物接线图:
2.png

  
  图中的板子,都是淘宝上淘来的,其中控制板150元左右、DCDC模块2元左右,电子开关不到1元。
1.水弹枪

  《绝地求生》装备M416全自动步枪,许多年前买的,不记得多少钱了,原先还有很多附件,都丢光了。破是破了点,但还能打,玩起来很解压。靠2节18650电池驱动(3.7+3.7V=7.4V),时间久了,电池也已经失效,因此,从go2的12v输出取电,通过一个可调DC-DC降压模块给枪供电。
2.控制板

  以前买的一块开发板,STM32F103C8T6芯片+W5500以太网模块+2路CAN+2路485,价值150元左右,其实控制枪不用这么多功能,只要有W5500以太网模块和GPIO口输出的板子就行,GPIO口控制电子开关给枪供电。
3.DCDC模块

  把go2的12V直流电降为7.4V。
4.电子开关

  接收GPIO控制信号,打开或关闭枪的电源,枪有电就发射。(枪的扳机被我绑在击发位置)
 
控制程序


  • STM32CubeMX
3.png


  • 移植W5500驱动库
    -- 1. 下载W5500驱动库,gitee下载地址、github下载地址。将ioLibrary_Driver目录拷贝到你的工程下面。
    -- 2. 将ioLibrary_Driver\Ethernet目录下的3个文件及其头文件——w5500.c,wizchip_conf.c,socket.c,添加到你的工程中。
  • 控制程序
      该部分代码使用了FreeRTOS操作系统,监听UDP 5001端口,当接收到消息含有fire字符串是,PB7口持续1秒的高电平。也就是说当收到UDP消息fire的时候,M416枪开火1秒。
  1. /* USER CODE END Header_StartTaskSendMsg */
  2. void StartTaskGetMsg(void *argument)
  3. {
  4.   /* USER CODE BEGIN StartTaskSendMsg */
  5.   /* Infinite loop */
  6.   for(;;)
  7.   {
  8.                 do_udp();       
  9.                
  10.                 if (fired == 1)
  11.                 {
  12.                         HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_SET);
  13.                         osDelay(1000);
  14.                         HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_7);
  15.                         fired = 0;                       
  16.                 }
  17.                
  18.     osDelay(1000);
  19.                
  20.   }
  21.   /* USER CODE END StartTaskSendMsg */
  22. }
复制代码
myudp.c程序中定义了W5500的网络信息,监听端口、ip地址等,并处理接收到的消息。
myudp.h
  1. #ifndef MYUDP_H
  2. #define MYUDP_H
  3. #include "myudp.h"
  4. #include "main.h"
  5. #include "w5500.h"
  6. #include "socket.h"
  7. #include "wizchip_conf.h"
  8. #include "spi.h"
  9. #include <string.h>
  10. #define SOCK_UDPS 2
  11. extern uint8_t buff[128];
  12. extern uint8_t UDP_send_buff[128];
  13. extern uint8_t remote_ip[4];
  14. extern uint16_t remote_port;
  15. void UDPinit(void);
  16. void do_udp(void);
  17. void udp_send(uint8_t* data, uint8_t len);
  18. void Analysis(uint8_t *buf);
  19. #endif // MYUDP_H
复制代码
在这里可以修改你的IP地址,监听端口,处理接收到的消息。
myudp.c
  1. #include "myudp.h"
  2. #include "main.h"
  3. #include "w5500.h"
  4. #include "socket.h"
  5. #include "wizchip_conf.h"
  6. #include "spi.h"
  7. #include <string.h>
  8. uint8_t buff[128];
  9. uint8_t UDP_send_buff[128];
  10. uint8_t remote_ip[4] = {255,255,255,255};
  11. uint16_t remote_port = 8080;
  12. //片选
  13. void W5500_Select(void) {
  14.     HAL_GPIO_WritePin(SCSn_GPIO_Port, SCSn_Pin, GPIO_PIN_RESET);
  15. }
  16. void W5500_Unselect(void) {
  17.     HAL_GPIO_WritePin(SCSn_GPIO_Port, SCSn_Pin, GPIO_PIN_SET);
  18. }
  19. void W5500_Restart(void) {
  20.     HAL_GPIO_WritePin(RSTn_GPIO_Port, RSTn_Pin, GPIO_PIN_RESET);
  21.     HAL_Delay(1);  // delay 1ms
  22.     HAL_GPIO_WritePin(RSTn_GPIO_Port, RSTn_Pin, GPIO_PIN_SET);
  23.     HAL_Delay(1600);  // delay 1600ms
  24. }
  25. void W5500_ReadBuff(uint8_t* buff, uint16_t len) {
  26.     HAL_SPI_Receive(&hspi2, buff, len, HAL_MAX_DELAY);
  27. }
  28. void W5500_WriteBuff(uint8_t* buff, uint16_t len) {
  29.     HAL_SPI_Transmit(&hspi2, buff, len, HAL_MAX_DELAY);
  30. }
  31. uint8_t W5500_ReadByte(void) {
  32.     uint8_t byte;
  33.     W5500_ReadBuff(&byte, sizeof(byte));
  34.     return byte;
  35. }
  36. void W5500_WriteByte(uint8_t byte) {
  37.     W5500_WriteBuff(&byte, sizeof(byte));
  38. }
  39. //配置W5500网络信息
  40. wiz_NetInfo gSetNetInfo = {
  41.   .mac  = {0x00, 0x08, 0xdc, 0x11, 0x11, 0x11},
  42.   .ip   = {192, 168, 123, 55},
  43.   .sn   = {255, 255, 255, 0},
  44.   .gw   = {192, 168, 123, 1},
  45.   .dns  = {144, 144, 144, 144},
  46.   .dhcp = NETINFO_STATIC};
  47. wiz_NetInfo gGetNetInfo;
  48. enum Status
  49. {
  50.   Failed = 0,
  51.   Success = 1
  52. };
  53. /**
  54. * @brief valid the result of set net info
  55. * @return 1: Success
  56. *         0: Failed
  57. */
  58. uint8_t validSetNetInfoResult(wiz_NetInfo* _set, wiz_NetInfo* _get)
  59. {
  60.   return (!memcmp(_set, _get, sizeof(wiz_NetInfo)));  // if same, memcmp return 0
  61. }
  62. void UDPinit(void)
  63. {
  64.   reg_wizchip_cs_cbfunc(W5500_Select, W5500_Unselect);
  65.   reg_wizchip_spi_cbfunc(W5500_ReadByte, W5500_WriteByte);
  66.   W5500_Restart();  // hardware restart through RESET pin
  67.   ctlnetwork(CN_SET_NETINFO, (void*)&gSetNetInfo);  // set net info
  68.   // maybe need delay
  69.   ctlnetwork(CN_GET_NETINFO, (void*)&gGetNetInfo);  // get net info
  70.   // W5500 has 8 channel, 32k buffer, 2 means 2KBytes
  71.   uint8_t buffer_size_8channel_tx_rx[16] = {2, 2, 2, 2, 2, 2, 2, 2,  // 8 channel tx
  72.                                             2, 2, 2, 2, 2, 2, 2, 2}; // 8 channel rx
  73.   if(ctlwizchip(CW_INIT_WIZCHIP,(void*)buffer_size_8channel_tx_rx))
  74.   {
  75.     // failed
  76.    
  77.   }
  78.   uint8_t sta = getSn_SR(SOCK_UDPS);
  79.   if(sta == SOCK_CLOSED)
  80.   {
  81.     socket(SOCK_UDPS, Sn_MR_UDP, 5001, 0);
  82.   }
  83.   HAL_Delay(100);
  84. }
  85. void do_udp(void)
  86. {                                                              
  87.         uint16_t len=0;       
  88.         switch(getSn_SR(SOCK_UDPS))       /*获取socket的状态*/
  89.         {
  90.                 case SOCK_CLOSED:                 /*socket处于关闭状态*/
  91.                         socket(SOCK_UDPS,Sn_MR_UDP,5001,0);    /*初始化socket*/
  92.                   break;
  93.                
  94.                 case SOCK_UDP:      /*socket初始化完成*/
  95.                         HAL_Delay(10);  
  96.                         if(getSn_IR(SOCK_UDPS) & Sn_IR_RECV) //检查是否有接收中断
  97.                         {
  98.                                 setSn_IR(SOCK_UDPS, Sn_IR_RECV);  /*清接收中断*/
  99.                         }
  100.                         if((len=getSn_RX_RSR(SOCK_UDPS))>0)  /*接收到数据*/
  101.                         {
  102.                                 recvfrom(SOCK_UDPS,buff, len, remote_ip,&remote_port);               /*W5500接收计算机发送来的数据W5500接收计算机发送来的数据,并获取发送方的IP地址和端口号*/
  103.                                 sendto(SOCK_UDPS,buff,len-8, remote_ip, remote_port);                /*W5500把接收到的数据发送*/
  104.         Analysis(buff);//分析数据
  105.         memset(buff, 0, sizeof(buff));
  106.                         }
  107.                         break;
  108.         }
  109. }
  110. void udp_send(uint8_t* data,uint8_t len)
  111. {
  112.   sendto(SOCK_UDPS, data, len, remote_ip, remote_port);
  113.   memset(data, 0, len);
  114. }
  115. void SystemReset() {
  116.     __HAL_RCC_BACKUPRESET_FORCE(); // 强制备份域复位
  117.     __HAL_RCC_BACKUPRESET_RELEASE(); // 释放备份域复位
  118.     NVIC_SystemReset(); // 发起系统复位
  119. }
  120. void Analysis(uint8_t *buf)
  121. {
  122.         char * gun = "fire";
  123.         char * result = strstr((char*)buf, gun);
  124.         if (result != NULL)
  125.         {
  126.                 fired =1;               
  127.                 return;
  128.         }
  129.        
  130.         char * devreset ="reset";
  131.         result = strstr((char*)buf, devreset);
  132.         if (result != NULL)
  133.         {
  134.                         SystemReset();
  135.                         return;
  136.         }
  137. }
复制代码
 
待续

  预祝您,成功将以上代码烧写进你的板子中。接下来,我们开始给go2扩展坞写ROS2程序,让它能够通过原厂遥控器击发开火功能。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

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