导语
作为本系列的开篇,有必要先做些约定:
- 以后的内容仅提供核心功能的代码,尽可能简洁,毕竟每个狗主都会有自己的想法,会添加自己的功能,写太多不容易整合,更何况我也没做什么复杂功能。
- 提供的代码片段不进行过多解释,程序语言也是语言,“领会精神“”就好。
- 不管是硬件设计还是软件编程部分,咱遵循三哥军工的设计思路,能依赖现有软件功能的就绝不自己编码,能购买的电子模块绝不自己动手制作。
- 机器人操作系统采用Ros2 Foxy,软件编程使用python语言,硬件编程c语言,操作系统Ubuntu 20.04。
功能
这里的功能仅指与架枪相关的功能。(水弹枪是儿子友情赞助的,请勿对人射击。)
- 通过3D打印机打印支架和电器盒子,固定枪和电路板。
- 由go2的扩展坞发送UDP广播消息给控制电路,击发开火。
- 编程实现原厂遥控器的向上按钮作为开火键。
- 用cv2实现一个简单的人脸识别系统。
- 实现一个deepseek agent功能,让go2能理解你发出的指令,并按照你的指令执行任务(如,找到张三,立即开火。 或者 打个招呼 ...)
硬件
先上图,实物接线图:
图中的板子,都是淘宝上淘来的,其中控制板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控制信号,打开或关闭枪的电源,枪有电就发射。(枪的扳机被我绑在击发位置)
控制程序
- 移植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秒。
- /* USER CODE END Header_StartTaskSendMsg */
- void StartTaskGetMsg(void *argument)
- {
- /* USER CODE BEGIN StartTaskSendMsg */
- /* Infinite loop */
- for(;;)
- {
- do_udp();
-
- if (fired == 1)
- {
- HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_SET);
- osDelay(1000);
- HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_7);
- fired = 0;
- }
-
- osDelay(1000);
-
- }
- /* USER CODE END StartTaskSendMsg */
- }
复制代码 myudp.c程序中定义了W5500的网络信息,监听端口、ip地址等,并处理接收到的消息。
myudp.h- #ifndef MYUDP_H
- #define MYUDP_H
- #include "myudp.h"
- #include "main.h"
- #include "w5500.h"
- #include "socket.h"
- #include "wizchip_conf.h"
- #include "spi.h"
- #include <string.h>
- #define SOCK_UDPS 2
- extern uint8_t buff[128];
- extern uint8_t UDP_send_buff[128];
- extern uint8_t remote_ip[4];
- extern uint16_t remote_port;
- void UDPinit(void);
- void do_udp(void);
- void udp_send(uint8_t* data, uint8_t len);
- void Analysis(uint8_t *buf);
- #endif // MYUDP_H
复制代码 在这里可以修改你的IP地址,监听端口,处理接收到的消息。
myudp.c- #include "myudp.h"
- #include "main.h"
- #include "w5500.h"
- #include "socket.h"
- #include "wizchip_conf.h"
- #include "spi.h"
- #include <string.h>
- uint8_t buff[128];
- uint8_t UDP_send_buff[128];
- uint8_t remote_ip[4] = {255,255,255,255};
- uint16_t remote_port = 8080;
- //片选
- void W5500_Select(void) {
- HAL_GPIO_WritePin(SCSn_GPIO_Port, SCSn_Pin, GPIO_PIN_RESET);
- }
- void W5500_Unselect(void) {
- HAL_GPIO_WritePin(SCSn_GPIO_Port, SCSn_Pin, GPIO_PIN_SET);
- }
- void W5500_Restart(void) {
- HAL_GPIO_WritePin(RSTn_GPIO_Port, RSTn_Pin, GPIO_PIN_RESET);
- HAL_Delay(1); // delay 1ms
- HAL_GPIO_WritePin(RSTn_GPIO_Port, RSTn_Pin, GPIO_PIN_SET);
- HAL_Delay(1600); // delay 1600ms
- }
- void W5500_ReadBuff(uint8_t* buff, uint16_t len) {
- HAL_SPI_Receive(&hspi2, buff, len, HAL_MAX_DELAY);
- }
- void W5500_WriteBuff(uint8_t* buff, uint16_t len) {
- HAL_SPI_Transmit(&hspi2, buff, len, HAL_MAX_DELAY);
- }
- uint8_t W5500_ReadByte(void) {
- uint8_t byte;
- W5500_ReadBuff(&byte, sizeof(byte));
- return byte;
- }
- void W5500_WriteByte(uint8_t byte) {
- W5500_WriteBuff(&byte, sizeof(byte));
- }
- //配置W5500网络信息
- wiz_NetInfo gSetNetInfo = {
- .mac = {0x00, 0x08, 0xdc, 0x11, 0x11, 0x11},
- .ip = {192, 168, 123, 55},
- .sn = {255, 255, 255, 0},
- .gw = {192, 168, 123, 1},
- .dns = {144, 144, 144, 144},
- .dhcp = NETINFO_STATIC};
- wiz_NetInfo gGetNetInfo;
- enum Status
- {
- Failed = 0,
- Success = 1
- };
- /**
- * @brief valid the result of set net info
- * @return 1: Success
- * 0: Failed
- */
- uint8_t validSetNetInfoResult(wiz_NetInfo* _set, wiz_NetInfo* _get)
- {
- return (!memcmp(_set, _get, sizeof(wiz_NetInfo))); // if same, memcmp return 0
- }
- void UDPinit(void)
- {
- reg_wizchip_cs_cbfunc(W5500_Select, W5500_Unselect);
- reg_wizchip_spi_cbfunc(W5500_ReadByte, W5500_WriteByte);
- W5500_Restart(); // hardware restart through RESET pin
- ctlnetwork(CN_SET_NETINFO, (void*)&gSetNetInfo); // set net info
- // maybe need delay
- ctlnetwork(CN_GET_NETINFO, (void*)&gGetNetInfo); // get net info
- // W5500 has 8 channel, 32k buffer, 2 means 2KBytes
- uint8_t buffer_size_8channel_tx_rx[16] = {2, 2, 2, 2, 2, 2, 2, 2, // 8 channel tx
- 2, 2, 2, 2, 2, 2, 2, 2}; // 8 channel rx
- if(ctlwizchip(CW_INIT_WIZCHIP,(void*)buffer_size_8channel_tx_rx))
- {
- // failed
-
- }
- uint8_t sta = getSn_SR(SOCK_UDPS);
- if(sta == SOCK_CLOSED)
- {
- socket(SOCK_UDPS, Sn_MR_UDP, 5001, 0);
- }
- HAL_Delay(100);
- }
- void do_udp(void)
- {
- uint16_t len=0;
- switch(getSn_SR(SOCK_UDPS)) /*获取socket的状态*/
- {
- case SOCK_CLOSED: /*socket处于关闭状态*/
- socket(SOCK_UDPS,Sn_MR_UDP,5001,0); /*初始化socket*/
- break;
-
- case SOCK_UDP: /*socket初始化完成*/
- HAL_Delay(10);
- if(getSn_IR(SOCK_UDPS) & Sn_IR_RECV) //检查是否有接收中断
- {
- setSn_IR(SOCK_UDPS, Sn_IR_RECV); /*清接收中断*/
- }
- if((len=getSn_RX_RSR(SOCK_UDPS))>0) /*接收到数据*/
- {
- recvfrom(SOCK_UDPS,buff, len, remote_ip,&remote_port); /*W5500接收计算机发送来的数据W5500接收计算机发送来的数据,并获取发送方的IP地址和端口号*/
- sendto(SOCK_UDPS,buff,len-8, remote_ip, remote_port); /*W5500把接收到的数据发送*/
- Analysis(buff);//分析数据
- memset(buff, 0, sizeof(buff));
- }
- break;
- }
- }
- void udp_send(uint8_t* data,uint8_t len)
- {
- sendto(SOCK_UDPS, data, len, remote_ip, remote_port);
- memset(data, 0, len);
- }
- void SystemReset() {
- __HAL_RCC_BACKUPRESET_FORCE(); // 强制备份域复位
- __HAL_RCC_BACKUPRESET_RELEASE(); // 释放备份域复位
- NVIC_SystemReset(); // 发起系统复位
- }
- void Analysis(uint8_t *buf)
- {
- char * gun = "fire";
- char * result = strstr((char*)buf, gun);
- if (result != NULL)
- {
- fired =1;
- return;
- }
-
- char * devreset ="reset";
- result = strstr((char*)buf, devreset);
- if (result != NULL)
- {
- SystemReset();
- return;
- }
- }
复制代码
待续
预祝您,成功将以上代码烧写进你的板子中。接下来,我们开始给go2扩展坞写ROS2程序,让它能够通过原厂遥控器击发开火功能。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |