站内搜索
发作品签到
一只“有表情”的机器狗!STM32+NFR24L01遥控宠物
专业版

一只“有表情”的机器狗!STM32+NFR24L01遥控宠物

简介

基于STM32F103C8T6单片机与NRF24L01射频模块设计的遥控机器狗以及遥控器,可以实现遥控机器狗的运动与表情显示

简介:基于STM32F103C8T6单片机与NRF24L01射频模块设计的遥控机器狗以及遥控器,可以实现遥控机器狗的运动与表情显示

开源协议

MIT License

(未经作者授权,禁止转载)
创建时间:2026-03-06 20:11:56更新时间:2026-03-25 09:54:49

描述

项目简介

本项目设计并实现了一套完整的无线遥控器狗系统。STM32F103C8T6为核心,结合NRF24L01 2.4GHz无线射频模块设计了机器狗的控制板与遥控器

项目功能

本项目设计并实现了一款基于STM32F103C8T6单片机与NRF24L01射频模块的智能遥控机器狗系统。系统采用主从式架构,手持遥控器通过2.4GHz无线通信向机器狗发送控制指令,机器狗接收指令后实时驱动多路舵机实现前进、后退、转向等多种仿生步态;同时,机器狗面部搭载的OLED屏可根据运行状态或遥控指令动态显示预设表情(如高兴、疑惑、睡眠等),实现直观的人机交互。

项目参数

本项目硬件系统主要由主控芯片、无线通信模块、运动执行模块及显示交互模块构成:

  • 核心控制采用两片STM32F103C8T6单片机,分别负责机器狗的运动与表情驱动、遥控器的指令采集与协议处理;

  • 无线通信选用NRF24L01 2.4G无线模块,确保稳定传输;

1a75f097d18382430166c4fa1e830465.png

  • 运动执行部分由4个舵机(SG90)构成,通过PWM信号精确控制机器狗的关节动作;
  • 显示交互方面,机器狗面部搭载0.96英寸OLED显示屏,用于动态显示多种表情
  • 遥控器可选配0.96英寸OLED显示屏实时显示控制参数与机器狗状态;此外,系统还包含电源管理模块、摇杆、按键、电池等基础元器件,共同构成完整的遥控机器狗系统。

微信图片_20260306220541_339_94.jpg

遥控器图片

微信图片_20260306220543_340_94.png

摇杆图片

软件代码

遥控器代码

#include "delay.h"
#include "oled.h"
#include "stm32f10x.h"                  // Device header
#include "nrf24l01.h"
#include "stdio.h"


// 初始化ADC1,用于PB0(ADC1_CH8)和PB1(ADC1_CH9)
void ADC1_Init(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    
    // 使能GPIO和ADC时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_ADC1, ENABLE);
    
    // 配置PB0和PB1为模拟输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;  // 模拟输入模式
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // ADC配置
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;  // 独立模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;       // 禁止扫描模式
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  // 单次转换模式
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  // 软件触发
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  // 数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 1;  // 转换通道数量
    ADC_Init(ADC1, &ADC_InitStructure);
    
    // 使能ADC1
    ADC_Cmd(ADC1, ENABLE);
    
    // 校准ADC
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));
}


void tim2_init(void)
{
	TIM_TimeBaseInitTypeDef tim;
	NVIC_InitTypeDef nvic;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	tim.TIM_ClockDivision=TIM_CKD_DIV1;
	tim.TIM_CounterMode=TIM_CounterMode_Up;
	tim.TIM_Period=10000-1;
	tim.TIM_Prescaler=7200-1;
	tim.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&tim);
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	nvic.NVIC_IRQChannel=TIM2_IRQn;
	nvic.NVIC_IRQChannelCmd=ENABLE;
	nvic.NVIC_IRQChannelPreemptionPriority=0;
	nvic.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&nvic);
	
	TIM_Cmd(TIM2,ENABLE);
	
}

// 读取指定通道的ADC值
uint16_t ADC1_ReadChannel(uint8_t channel) {
    // 配置ADC通道转换顺序和采样时间
    ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_55Cycles5);
    
    // 启动ADC转换
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    
    // 等待转换完成
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
    
    // 返回转换结果
    return ADC_GetConversionValue(ADC1);
}

// 将ADC值转换为电压值(mV)
uint16_t ADC_ConvertToVoltage(uint16_t adcValue) {
    // 假设参考电压为3.3V,ADC为12位
    return (uint16_t)((adcValue * 3300) / 4095);
}

int main(void) {
    uint16_t pb0AdcValue, pb1AdcValue;
    uint16_t pb0Voltage, pb1Voltage;
	  uint16_t status,last_status;
	  last_status=0xff;
	
	  NRF24L01_TxPacket[0]=0xff;
	  NRF24L01_TxPacket[1]=0x01;
	  NRF24L01_TxPacket[2]=0x02;
	  NRF24L01_TxPacket[3]=0x03;
    
    // 初始化ADC
    ADC1_Init();
	  OLED_Init();
	  NRF24L01_Init();  // 初始化NRF24L01
	  NRF24L01_Tx();    //发送模式
    
    while(1) 
			{
        // 读取PB0(ADC1_CH8)的电压
        pb0AdcValue = ADC1_ReadChannel(ADC_Channel_8);
        pb0Voltage = ADC_ConvertToVoltage(pb0AdcValue);
        
        // 读取PB1(ADC1_CH9)的电压
        pb1AdcValue = ADC1_ReadChannel(ADC_Channel_9);
        pb1Voltage = ADC_ConvertToVoltage(pb1AdcValue);
        
			  OLED_ShowString(1,1,"x:");
			  OLED_ShowString(1,8,"y:");
			  OLED_ShowNum(1,3,pb0Voltage,4);
			  OLED_ShowNum(1,10,pb1Voltage,4);
			
			if(pb0Voltage<1500)
			{
				status=0x00;//后退
			}
			else if(pb0Voltage>1750)
			{
				status=0x01;//前进
			}
			else if((pb1Voltage<1500)&(pb0Voltage<1750)&(pb0Voltage>1500))
			{
				status=0x02;//左转

			}
			else if((pb1Voltage>1750)&(pb0Voltage<1750)&(pb0Voltage>1500))
			{
				status=0x03;//右转
			}
			else if((pb1Voltage>1500)&(pb1Voltage<1750)&(pb0Voltage<1750)&(pb0Voltage>1500))
			{
				status=0x04;//原地
			}
			
			NRF24L01_TxPacket[0]=status;
			NRF24L01_Send();
			
			if(status!=last_status)
			{
				last_status=status;
				if(status==0x00)
				{
					OLED_Clear();
					OLED_ShowString(3,4,"GO GO GO!");
				}
				else if(status==0x01)
				{
					OLED_Clear();
					OLED_ShowString(3,7,"back");
				}
				else if(status==0x02)
				{
					OLED_Clear();
					OLED_ShowString(3,3,"turn right");
				}
				else if(status==0x03)
				{
					OLED_Clear();
					OLED_ShowString(3,3,"turn left");
				}
				else if(status==0x04)
				{
					OLED_Clear();
					OLED_ShowString(3,7,"rest");
				}
			}
			
			
			
    }
}

这段代码主要实现以下功能:

  • 由于摇杆的本质是两个滑动变阻器对Vcc分压,因此通过ADC1采集PB0(通道8)和PB1(通道9)的模拟电压值即可以侧面反映摇杆的方位。

  • 将ADC值转换为电压值(单位mV)并通过OLED显示屏实时显示。

  • 根据两个电压值的范围(即摇杆的状态)判断当前状态(前进、后退、左转、右转、原地),并通过NRF24L01无线模块发送状态码。

  • OLED上会显示当前状态对应的文本提示。

控制板代码

#include "delay.h"
#include "oled.h"
#include "stm32f10x.h"                  // Device header
#include "nrf24l01.h"
#include "Dynamics.h"
#include "stdio.h"
#include "emoj.h"



int main(void)
{
	SystemInit();
	delay_init();
        OLED_Init();
	
	Dynamics_Init();
	NRF24L01_Init();
	tyq_init();

	
	while(1)
	{
	

NRF24L01_Receive();
		
		if(NRF24L01_ReadStatus())
		{
		switch(NRF24L01_RxPacket[0])
		{
			case 0x04: 
				stand();  
OLED_ShowFullImage(13);			
			;break;
			
			case 0x01: 
				back(); 
        OLED_ShowFullImage(14);			
			;break;
			
			case 0x00: 
				go();
			OLED_ShowFullImage(15);	
				;break;
			case 0x02: 
				turn_right();
			OLED_ShowFullImage(16);
				;break;
			case 0x03:   
				turn_left();
			OLED_ShowFullImage(16);
				;break;
			default:
				stand();
		}
	}

该代码主要实现以下功能:

  • 初始化系统时钟、延时、OLED显示屏、动力学控制模块(Dynamics_Init())、NRF24L01无线模块等等。

  • 在主循环中,通过NRF24L01不断接收无线数据。当接收到有效数据时,根据数据包的第一个字(NRF24L01_RxPacket[0])的值,执行相应的动作函数(如前进、后退、转向、停止),并在OLED上显示对应的全屏表情图像。

实物图

机器狗的图片(未装OLED)

屏幕截图 2026-03-06 221053.png

其他

完整代码详见附件

设计图

未生成预览图,请在编辑器重新保存一次

BOM

暂无BOM

3D模型

序号文件名称下载次数
暂无数据

附件

序号文件名称下载次数
1
演示视频与代码.zip
12
克隆工程
添加到专辑
0
0
分享
侵权投诉
知识产权声明&复刻说明

本项目为开源硬件项目,其相关的知识产权归创作者所有。创作者在本平台上传该硬件项目仅供平台用户用于学习交流及研究,不包括任何商业性使用,请勿用于商业售卖或其他盈利性的用途;如您认为本项目涉嫌侵犯了您的相关权益,请点击上方“侵权投诉”按钮,我们将按照嘉立创《侵权投诉与申诉规则》进行处理。

请在进行项目复刻时自行验证电路的可行性,并自行辨别该项目是否对您适用。您对复刻项目的任何后果负责,无论何种情况,本平台将不对您在复刻项目时,遇到的任何因开源项目电路设计问题所导致的直接、间接等损害负责。

底部导航