2019年12月初,有一箇中國機器人技能大賽中的雙足機器人比賽項目,意思是機器人識別音樂跳對應節奏的舞蹈,五首音樂隨機抽三首歌曲,音樂停,機器人停。html
新比賽,新項目,難度天然有,坑也很多。但願這篇文章能給你們帶來一點幫助。廢話很少說,進入正題。node
(健康歌)每100ms採樣一次,歌曲前5秒內共測50次數據,重複12組web
(卡路里) 重複7組windows
能夠看出一首歌通過屢次測值,其採樣值數組呈現出有規律的特徵;不一樣的歌曲的特徵也有較好的區分度。達到了區分歌曲的效果。下面講講具體實現步驟。數組
找到一塊具備模擬量輸出功能的聲音傳感器模塊,我用的是下面這塊,感受不錯,其餘的沒嘗試過。將f103芯片的A1腳與模塊的AOUT引腳相連(奇怪的是我與DOUT相連也會獲得和AOUT差很少的模擬量值,很迷,有大佬懂的話麻煩指出一下問題所在)。app
利用正點原子的adc.c文件來處理模擬量值,並最終返回給Get_Adc_Average()函數less
//初始化ADC
//這裏咱們僅以規則通道爲例
//咱們默認將開啓通道0~3
void Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//使能ADC1通道時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//設置ADC分頻因子6 72M/6=12,ADC最大時間不能超過14M
//PA1 做爲模擬通道輸入引腳
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模擬輸入引腳
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_DeInit(ADC1); //復位ADC1
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
//ADC工做模式:ADC1和ADC2工做在獨立模式
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數據右對齊
ADC_InitStructure.ADC_NbrOfChannel = 1;//順序進行規則轉換的ADC通道的數目
ADC_Init(ADC1, &ADC_InitStructure);
//根據ADC_InitStruct中指定的參數初始化外設ADCx的寄存器
ADC_Cmd(ADC1, ENABLE);//使能指定的ADC1
ADC_ResetCalibration(ADC1);//使能復位校準
while(ADC_GetResetCalibrationStatus(ADC1));//等待復位校準結束
ADC_StartCalibration(ADC1); //開啓AD校準
while(ADC_GetCalibrationStatus(ADC1)); //等待校準結束
//ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能指定的ADC1的軟件轉換啓動功能
}
//得到ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)
{
//設置指定ADC的規則組通道,一個序列,採樣時間
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );
//ADC1,ADC通道,採樣時間爲239.5週期
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能指定的ADC1的軟件轉換啓動功能
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待轉換結束
return ADC_GetConversionValue(ADC1);//返回最近一次ADC1規則組的轉換結果
}
u16 Get_Adc_Average(u8 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}
將Get_Adc_Average()拿到的值經過串口輸出在電腦屏幕上,適當調整其數值範圍,刷新時間間隔。我在代碼中就進行了(4093-adcx),(delay_ms(100))相關處理。ide
xxxxxxxxxx
while(1)
{
printf("\r\n");
for(i=0;;i++)
{
for(j=0;j<50;j++)
{
adcx=Get_Adc_Average(ADC_Channel_1,10);
printf("%-4d \r",4093-adcx);
delay_ms(100);
}
printf("\r\n");
delay_ms(1500);
delay_ms(1500);
}
}
判斷歌曲就更簡單了,把採樣值存入數組,寫一個條件語句判斷數組的特徵就行了,以下:svg
xxxxxxxxxx
u8 check_song(void)
{
u16 adcx,adc[35]={0};
u8 i,flag=0;
printf("\r\n");
for(i=0;i<35;i++)//存儲數據
{
adcx=CurrentAdc();
adc[i]=adcx;
if (adc[i]>300)
flag++;
printf("%-4d \r", adc[i]);
delay_ms(100);
}
if(flag>32)
{
printf("flag%d\r",flag);
return 0;//太極拳
}
else
{
printf("flag%d\r",flag);
if((adc[23]<5&&adc[24]<5)
||(adc[24]<5&&adc[25]<5)
||(adc[25]<5&&adc[26]<5)
||(adc[26]<5&&adc[27]<5)
||(adc[27]<5&&adc[28]<5))
return 1;//健康歌
else return 2;//翻跟頭
}
}
一看到比賽項目的時候,臥槽,感受很難,果真網上一查,什麼資料也沒有。。絕望,想放棄。。比賽前半個月,老師開始問進度了,很慌,啥也沒有。但很差意思空手去,因而和隊友總結出上面幾套方案,發現有個保命方案,內心稍微有點底,開始去探索更好的方法。最後搞出來聲音的adc採集,其實如今看看代碼,實在是簡單,慚愧慚愧。其實比賽現場能真正識別出音樂的不超過10個(共30個隊伍),我難人亦難,但我只要去作,山重水複疑無路,柳暗花明又一村。這已超過了很多的人,最重要的是打敗了本身。必定要去作,用心作!函數
準備過程當中是不可能一路順風的,一天一個小自閉,三天一個大自閉,燒板子查不出問題,斷結構從新打印,破代碼運行不出效果,軟件崩潰文件沒保存......簡直懷疑人生。。通常遇到這時候,放下手中的工做,跑個步,洗個澡,吃個飯,歸來仍是少年。作人嘛,最重要的就是心態好啦。
現階段自身的能力還不足以輸出不少很好的內容。模仿大佬,總結經驗是比較好的成長路線。慢慢地就會有本身的風格了。加油!