利用arduino UNO配合Orangepi 4B實現製作機器人

2020-10-03 12:01:26

在上一個部落格的最後我提到了利用Orangepi 4B製作機器人(傳送門)

傳送門
上一個部落格的中心是Orangepi 4B
這個部落格則是以arduino配合Orangepi 4B完成電機驅動舵機等的操作

在這部分需要有更多的準備

知識儲備

1.C語言/C++基礎
2.arduino IDE軟體的基本操作
3.arduino中json庫(ArduinoJson.h)和多執行緒庫(scoop.h)的使用
4.arduino中UART通訊的方法
5.python中串列埠通訊庫(pyserial)和執行緒庫(threading)的使用

硬體方面準備

上一個部落格(見上方傳送門)中的所有硬體外加一張arduino uno微控制器(mega328p)幾根杜邦線、一個兩路電機驅動晶片、兩個電機,一個萬向滾珠、一個底座(實際上底盤可以根據經濟決定好壞)當然你也可以再加上一些採集模組讓你的機器人功能更豐富,我這裡加裝了一個DHT11模組(溫溼度採集)。

軟體方面準備

下載arduino IDE軟體可在arduino中文社群下載中文社群
裡面集中著各種arduino大佬
需要準備庫我給大家準備好了大家解壓到Arduino\libraries目錄下即可
集合下載地址提取碼:3101
python環境下需要下載對執行緒庫(threading)以及串列埠通訊庫(pyserial)
下載方式為開啟終端輸入以下命令

	pip install threading
	pip install pyserial

開始實作

arduino微控制器程式編寫

#include <ArduinoJson.h>  	//載入庫檔案
#include <math.h>
#include <SCoop.h>
#include <dht11.h>
#define DHT11PIN 10 		//定義模組埠
dht11 DHT11;				//範例化 DHT模組

int beep=8;					//蜂鳴器引腳定義
int speedleft=5;			//左電機速度引腳定義
int speedright=6;			//右電機速度引腳定義
int left_motor_go=3;		//左電機正轉引腳定義
int right_motor_go=4;		//右電機正轉引腳定義
int left_motor_back=2;		//左電機反轉引腳定義
int right_motor_back=7;		//右電機反轉引腳定義

char control1="停止";		//儲存小車控制命令,初始命令為停止

StaticJsonBuffer<200> jsonsendBuffer;  //建立json buffer空間
JsonObject& root = jsonsendBuffer.createObject();//將root定義為json變數

String line ="";			//建立字串變數儲存串列埠接收到的字串

defineTaskLoop(myTask1)		//任務執行緒1每隔一秒
{
 DHT11.read(DHT11PIN);      //讀取溫溼度
 float tem=(float)DHT11.temperature;               //將溫度值賦值給tem
 float hum=(float)DHT11.humidity;                   //將溼度值賦給hum  
 root["Tempeature"]=tem;
 root["Humidity"]=hum; 
 root.printTo(Serial);		//延時一段時間
 sleep(1000);                //延時一段時間
}

void forward()//小車前進
{
  digitalWrite(left_motor_go,HIGH); 	 //左電機正轉
  digitalWrite(left_motor_back,LOW); 
  digitalWrite(right_motor_go,HIGH); 	 //右電機正轉
  digitalWrite(right_motor_back,LOW);  
}

void backward()//小車後退
{
  digitalWrite(left_motor_go,LOW);		  //左電機反轉
  digitalWrite(left_motor_back,HIGH); 
  digitalWrite(right_motor_go,LOW);		  //右電機反轉
  digitalWrite(right_motor_back,HIGH); 
}

void right()//小車單輪左轉
{
  digitalWrite(left_motor_go,LOW);  	  //左電機停止
  digitalWrite(left_motor_back,LOW); 
  digitalWrite(right_motor_go,HIGH); 	  //右電機正轉
  digitalWrite(right_motor_back,LOW);  
}


void left()								  //小車單輪右轉
{
  digitalWrite(left_motor_go,HIGH); 	  //左電機正轉
  digitalWrite(left_motor_back,LOW); 
  digitalWrite(right_motor_go,LOW); 	  //右電機停止
  digitalWrite(right_motor_back,LOW);     
}
void stopcar()//停車
{
  digitalWrite(left_motor_go,LOW); 		  //左電機停止
  digitalWrite(left_motor_back,LOW); 
  digitalWrite(right_motor_go,LOW);  	  //右電機停止
  digitalWrite(right_motor_back,LOW);
}
void goright()//小車原地左轉
{
  digitalWrite(left_motor_go,LOW);		  //左電機反轉
  digitalWrite(left_motor_back,HIGH); 
  digitalWrite(right_motor_go,HIGH); 	  //右電機正轉
  digitalWrite(right_motor_back,LOW); 
}
void goleft()//小車原地右轉
{
  digitalWrite(left_motor_go,HIGH);		 //左電機正轉
  digitalWrite(left_motor_back,LOW); 
  digitalWrite(right_motor_go,LOW);      //右電機反轉
  digitalWrite(right_motor_back,HIGH); 
}



void setup() { 							//初始化
  Serial.begin(115200);
  pinMode(speedleft,OUTPUT);  			//設定引腳輸入輸出
  pinMode(speedright,OUTPUT);
  pinMode(left_motor_go,OUTPUT);
  pinMode(right_motor_go,OUTPUT);
  pinMode(left_motor_back,OUTPUT);
  pinMode(right_motor_back,OUTPUT);
  pinMode(beep,OUTPUT);
  analogWrite(speedleft,100);			//輸入模擬值進行設定速度
  analogWrite(speedright,100);
  mySCoop.start();
  digitalWrite(right_motor_back,HIGH); 
  delay(1000)
  digitalWrite(right_motor_back,LOW); 	//初始化完成蜂鳴器響一秒
  
}
 
void loop() {
  if(control1="goon")
    forward();
  else if(control1="goback")
    backward();
  else if(control1="turnleft")
    left();
  else if(control1="turnright")
    right();
  else if(control1="turnturnleft")
    goleft();
  else if(control1="turnternright")
    goright();
  else if(control1="stop")
    stopcar();
  else
    stopcar();
  yield();
}


void serialEvent()
{
  if(Serial.available()) //串列埠是否有資料?
  {   
    String line = Serial.readStringUntil('\r');
    StaticJsonBuffer<200> jsonreciveBuffer;
    JsonObject& data1 = jsonreciveBuffer.parseObject(line);
    control1=data1["control"];
    data1.printTo(Serial);   //測試時使用
  }
}
}

Orangepi 4B 程式編寫

依舊在是之前demo上修改
加上多執行緒函數建立執行緒監測從微控制器發來的資訊,並且加上對硬體控制的指令uart通訊等

import threading
import serial
from time import sleep
ser = serial.Serial('/dev/ttyS4', 115200, timeout=0.5)  #香橙派4B只開放使用uart4埠
def recv(serial):  
	while True:  
		data =serial.read(30)  
        if data != '':  
			Tempeature=json.loads(data).get('Tempeature');
 			Humidity=json.loads(data).get('Humidity'); 
interrupted = False

def signal_handler(signal, frame):
    global interrupted
    interrupted = True

def interrupt_callback():
    global interrupted
    return interrupted

# 回撥函數,語音識別在這裡實現,修改也是在這裡
def callbacks():
    global detector
    time.sleep(0.2)
    your_text=['哎,我在,你說','我來啦,我來啦,我來啦~','我是你的語音助手小貝']
    a=random.randint(1,3)
    print('小貝'+your_text[a])
    play('huda/xiaobeihuida'+ str(a) +'.wav')  # 為喚醒詞事先準備好的回答
    time.sleep(0.2)
    try:
        a = get_text()
        if a =='嗯' or '':
            pass
        else:
            print('你:'+a)
            if '前進' in a:
        	    controldata={'control':'goon'}
        	    control=json.dumps(controldata)
        	    ser.writ(control)
        	    b='前進'
            elif '後退' in a:
        	    controldata={'control':'goback'}
        	    control=json.dumps(controldata)
        	    ser.writ(control)
        	    b='後退'
            elif '左轉' in a:
        	    controldata={'control':'ternleft'}
        	    control=json.dumps(controldata)
        	    ser.writ(control)
        	    b='左轉'
            elif '右轉' in a:
        	    controldata={'control':'ternright'}
        	    control=json.dumps(controldata)
        	    ser.writ(control)
        	    b='右轉'
            elif '原地左轉圈' in a:
        	    controldata={'control':'turnternleft'}
        	    control=json.dumps(controldata)
        	    ser.writ(control)
        	    b='原地左轉圈'
            elif '原地右轉圈' in a:
        	    controldata={'control':'turnternright'}
        	    control=json.dumps(controldata)
        	    ser.writ(control)
        	    b='原地右轉圈'
            elif '停止' in a:
        	    controldata={'control':'stop'}
        	    control=json.dumps(controldata)
        	    ser.writ(control)
        	    b='停止'
            elif '室內溫度' in a:
        	    b='當前室內溫度為'+str(Tempeature)+'攝氏度'
            elif '室內溼度' in a:
        	    b='當前室內溼度為百分之'+str(Humidity)
            else:
        	    b =get_chat_text(a)
            print('小貝:'+b)
            c = get_voice(b)
            play(c)
    except Exception:
        print('小貝:我沒聽清楚,請重新說一下')
        c = get_voice('我沒聽清楚,請重新說一下')
        play(c)


@contextmanager
def no_alsa_error():
    try:
        asound = cdll.LoadLibrary('libasound.so')
        asound.snd_lib_error_set_handler(c_error_handler)
        yield
        asound.snd_lib_error_set_handler(None)
    except:
        yield
        pass


def wake_up():
    global detector
    model = 'xiaobeixiaobei.pmdl'  # 我的喚醒詞為 小貝小貝
    # 終止方法為ctrl+c
    signal.signal(signal.SIGINT, signal_handler)
    # 喚醒詞檢測函數,調整sensitivity引數可修改喚醒詞檢測的準確性
    detector = snowboydecoder.HotwordDetector(model, sensitivity=0.5)
    print('正在聆聽... 請說喚醒詞:小貝小貝')
    # main loop
    # 回撥函數 detected_callback=snowboydecoder.play_audio_file
    # 修改回撥函數可實現我們想要的功能
    detector.start(detected_callback=callbacks,  # 自定義回撥函數
                   interrupt_check=interrupt_callback,
                   sleep_time=0.03)
    # 釋放資源
    detector.terminate()
#程式入口
if __name__ == "__main__":
	thread = threading.Thread(target=recv,args=(ser,))
	thread.start()
    wake_up()