簡介
本項目的主要功能是通過定義星火1號開發(fā)板上相應(yīng)IO的電平狀態(tài),調(diào)試智能手機與星火一號開發(fā)板之間的WIFI通訊,從而通過手機輸入相關(guān)的命令,實現(xiàn)對麥克納姆輪四驅(qū)小車的移動控制(如下圖所示)
硬件介紹
開發(fā)板
使用 RT-Thread 星火 1 號 開發(fā)板開發(fā)本項目,各模塊在開發(fā)板中位置如圖所示
RSAPBEERY CONN
如上圖所示,開發(fā)板RSAPBEERY CONN中各引腳與對應(yīng)L298N中輸入輸出口的對應(yīng)關(guān)系
RW007 WIFI
供電方案
八節(jié)5號電池串聯(lián)提供12V電壓(兩個L298N,兩個電池盒共計16個電池):優(yōu)點是供電較為穩(wěn)定其,缺點是其重量過大,可能導(dǎo)致小車速度下降。
充電寶3.6V+升壓模塊升至12V:利用可調(diào)輸出電壓的升壓模塊可以輸出12V電壓供L298N使用。但是因為充電寶、升壓模塊不穩(wěn)定,其無法穩(wěn)定輸出12V電壓,故而舍棄此方案。
接線
接線如上圖所示,各個端口所對應(yīng)具體情況如下:
電源線:+12V接升壓模塊OUT+
GND接升壓模塊OUT-
GND接開發(fā)板GND
+5V接開發(fā)板+5V
邏輯控制
對于Motor_A(小車前輪的兩個電機)和Motor_B(小車前輪的兩個電機)的控制邏輯如下,其中本項目使用的是PIN,因此無需考慮PWM
杜邦線
紅色:通常用于連接電源正極或高電平信號。
黑色:通常用于連接電源負極或地線。
藍色、綠色、黃色等其他顏色:通常用于連接數(shù)據(jù)線或其他信號線,具體用途取決于具體的電路設(shè)計。
小車裝配
第一層:電池盒及電池
第二層:星火1號開發(fā)板
第三層:L298N電機驅(qū)動模塊、輪子、電機
軟件介紹
WIFI 完成初始化
static int i = 0;
int result = RT_EOK;
struct rt_wlan_info info;
rt_thread_mdelay(500);
熱點掃描
/* 執(zhí)行掃描 */
rt_sem_init(&scan_done,"scan_done",0,RT_IPC_FLAG_FIFO);
rt_wlan_register_event_handler(RT_WLAN_EVT_SCAN_REPORT, wlan_scan_report_hander,&i);
rt_wlan_register_event_handler(RT_WLAN_EVT_SCAN_DONE, wlan_scan_done_hander,RT_NULL);
if(rt_wlan_scan() == RT_EOK)
{
LOG_D("the scan is started... ");
}else
{
LOG_E("scan failed");
}
/*等待掃描完畢 /
rt_sem_take(&scan_done,RT_WAITING_FOREVER);
Join 網(wǎng)絡(luò)
/ 熱點連接 /
LOG_D("start to connect ap ...");
rt_sem_init(&net_ready, "net_ready", 0, RT_IPC_FLAG_FIFO);
/ 注冊 wlan ready 回調(diào)函數(shù) /
rt_wlan_register_event_handler(RT_WLAN_EVT_READY, wlan_ready_handler, RT_NULL);
/ 注冊 wlan 斷開回調(diào)函數(shù) /
rt_wlan_register_event_handler(RT_WLAN_EVT_STA_DISCONNECTED, wlan_station_disconnect_handler, RT_NULL);
/ 同步連接熱點 /
result = rt_wlan_connect(WLAN_SSID, WLAN_PASSWORD);
if (result == RT_EOK)
{
rt_memset(&info, 0, sizeof(struct rt_wlan_info));
/ 獲取當前連接熱點信息 /
rt_wlan_get_info(&info);
LOG_D("station information:");
print_wlan_information(&info,0);
/ 等待成功獲取 IP /
result = rt_sem_take(&net_ready, NET_READY_TIME_OUT);
if (result == RT_EOK)
{
LOG_D("networking ready!");
msh_exec("ifconfig", rt_strlen("ifconfig"));
}
else
{
LOG_D("wait ip got timeout!");
}
/ 回收資源 */
rt_wlan_unregister_event_handler(RT_WLAN_EVT_READY);
rt_sem_detach(&net_ready);
}
else
{
LOG_E("The AP(%s) is connect failed!", WLAN_SSID);
}
rt_thread_mdelay(5000);
LOG_D("ready to disconect from ap ...");
rt_wlan_disconnect();
自動連接
LOG_D("start to autoconnect ...");
wifi_autoconnect();
串口連接模塊
使用sscom5發(fā)送數(shù)據(jù),rt-studio平臺接收數(shù)據(jù),數(shù)據(jù)作為參數(shù)傳入到電機控制模塊
static const char send_data[] = "This is TCP Client from RT-Thread."; /* 發(fā)送用到的數(shù)據(jù) */
char recv_data;
#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 5
static rt_thread_t tid1 = RT_NULL;
static rt_thread_t tid2 = RT_NULL;
/ 線程2的入口函數(shù) */
static void thread2_entry(void *parameter)
{
int ret;
struct hostent *host;
int sock, bytes_received;
struct sockaddr_in server_addr;
const char url;
int port;
url = "192.168.43.96";
port = 8800;
/ 通過函數(shù)入口參數(shù)url獲得host地址(如果是域名,會做域名解析) /
host = gethostbyname(url);
/ 分配用于存放接收數(shù)據(jù)的緩沖 /
recv_data = rt_malloc(BUFSZ);
if (recv_data == RT_NULL)
{
rt_kprintf("No memoryn");
return;
}
/ 創(chuàng)建一個socket,類型是SOCKET_STREAM,TCP類型 /
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
/ 創(chuàng)建socket失敗 /
rt_kprintf("Socket errorn");
/ 釋放接收緩沖 /
rt_free(recv_data);
return;
}
/ 初始化預(yù)連接的服務(wù)端地址 */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr )host->h_addr);
rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
/ 連接到服務(wù)端 */
if (connect(sock, (struct sockaddr )&server_addr, sizeof(struct sockaddr)) == -1)
{
/ 連接失敗 /
rt_kprintf("Connect fail!n");
closesocket(sock);
/ 釋放接收緩沖 /
rt_free(recv_data);
return;
}
while (1)
{
/ 從sock連接中接收最大BUFSZ - 1字節(jié)數(shù)據(jù) /
bytes_received = recv(sock, recv_data, BUFSZ - 1, 0);
if (bytes_received < 0)
{
/ 接收失敗,關(guān)閉這個連接 /
closesocket(sock);
rt_kprintf("nreceived error,close the socket.rn");
/ 釋放接收緩沖 /
rt_free(recv_data);
break;
}
else if (bytes_received == 0)
{
/ 默認 recv 為阻塞模式,此時收到0認為連接出錯,關(guān)閉這個連接 /
closesocket(sock);
rt_kprintf("nreceived error,close the socket.rn");
/ 釋放接收緩沖 /
rt_free(recv_data);
break;
}
/ 有接收到數(shù)據(jù),把末端清零 /
recv_data[bytes_received] = '?';
if (strncmp(recv_data, "q", 1) == 0 || strncmp(recv_data, "Q", 1) == 0)
{
/ 如果是首字母是q或Q,關(guān)閉這個連接 /
closesocket(sock);
rt_kprintf("n got a 'q' or 'Q',close the socket.rn");
/ 釋放接收緩沖 /
rt_free(recv_data);
break;
}
else
{
/ 在控制終端顯示收到的數(shù)據(jù) /
rt_kprintf("nReceived data = %s ", recv_data);
}
/ 發(fā)送數(shù)據(jù)到sock連接 /
ret = send(sock, send_data, strlen(send_data), 0);
if (ret < 0)
{
/ 接收失敗,關(guān)閉這個連接 /
closesocket(sock);
rt_kprintf("nsend error,close the socket.rn");
rt_free(recv_data);
break;
}
else if (ret == 0)
{
/ 打印send函數(shù)返回值為0的警告信息 /
rt_kprintf("n Send warning,send function return 0.rn");
}
}
return;
rt_thread_mdelay(500);
}
/ 線程2 /
int thread2_sample(void)
{
/ 創(chuàng)建線程2,名稱是thread2,入口是thread2_entry /
tid2 = rt_thread_create("thread2",
thread2_entry, RT_NULL,
2048,
THREAD_PRIORITY, THREAD_TIMESLICE);
/ 如果獲得線程控制塊,啟動這個線程 /
if (tid2 != RT_NULL)
rt_thread_startup(tid2);
return 0;
}
MSH_CMD_EXPORT(thread2_sample, thread sample);
開發(fā)板IO引腳定義
/ 配置 控制電機引腳(L2980N1) /
#define PIN_Motor_PA0 GET_PIN(A, 0) // PA0 : define --> Motor1
#define PIN_Motor_PA8 GET_PIN(A, 8) // PA8 : define --> Motor1
#define PIN_Motor_PB15 GET_PIN(B, 15) // PB15: define --> Motor2
#define PIN_Motor_PB14 GET_PIN(B, 14) // PB14: define --> Motor2
/ 配置 控制電機引腳(L2980N2) /
#define PIN_Motor_PB2 GET_PIN(B, 2) // PB2 : define --> Motor3
#define PIN_Motor_PG6 GET_PIN(G, 6) // PG6 : define --> Motor3
#define PIN_Motor_PG7 GET_PIN(G, 7) // PG7 : define --> Motor4
#define PIN_Motor_PD7 GET_PIN(D, 7) // PD7 : define --> Motor4
/ 定義電機引腳宏 */
#define PIN_Motor1_A PIN_Motor_PA0
#define PIN_Motor1_B PIN_Motor_PA8
#define PIN_Motor2_A PIN_Motor_PB15
#define PIN_Motor2_B PIN_Motor_PB14
#define PIN_Motor3_A PIN_Motor_PB2
#define PIN_Motor3_B PIN_Motor_PG6
#define PIN_Motor4_A PIN_Motor_PG7
#define PIN_Motor4_B PIN_Motor_PD7
小車行駛控制
通過設(shè)置對應(yīng)IO引腳的高低電平,可以控制電機的轉(zhuǎn)動和停止,從而控制小車的前進,后退,左移和右移
/* 控制小車前進 /
void motor_forward(void) {
// 向前加速1s
rt_pin_write(PIN_Motor1_A, PIN_HIGH);
rt_pin_write(PIN_Motor1_B, PIN_LOW);
rt_pin_write(PIN_Motor2_A, PIN_HIGH);
rt_pin_write(PIN_Motor2_B, PIN_LOW);
rt_pin_write(PIN_Motor3_A, PIN_HIGH);
rt_pin_write(PIN_Motor3_B, PIN_LOW);
rt_pin_write(PIN_Motor4_A, PIN_HIGH);
rt_pin_write(PIN_Motor4_B, PIN_LOW);
rt_thread_mdelay(1000);
//停下
rt_pin_write(PIN_Motor1_A, PIN_LOW);
rt_pin_write(PIN_Motor1_B, PIN_LOW);
rt_pin_write(PIN_Motor2_A, PIN_LOW);
rt_pin_write(PIN_Motor2_B, PIN_LOW);
rt_pin_write(PIN_Motor3_A, PIN_LOW);
rt_pin_write(PIN_Motor3_B, PIN_LOW);
rt_pin_write(PIN_Motor4_A, PIN_LOW);
rt_pin_write(PIN_Motor4_B, PIN_LOW);
}
/ 控制小車后退 /
void motor_backward(void) {
// 向后加速1s
rt_pin_write(PIN_Motor1_A, PIN_LOW);
rt_pin_write(PIN_Motor1_B, PIN_HIGH);
rt_pin_write(PIN_Motor2_A, PIN_LOW);
rt_pin_write(PIN_Motor2_B, PIN_HIGH);
rt_pin_write(PIN_Motor3_A, PIN_LOW);
rt_pin_write(PIN_Motor3_B, PIN_HIGH);
rt_pin_write(PIN_Motor4_A, PIN_LOW);
rt_pin_write(PIN_Motor4_B, PIN_HIGH);
rt_thread_mdelay(1000);
//停下
rt_pin_write(PIN_Motor1_A, PIN_LOW);
rt_pin_write(PIN_Motor1_B, PIN_LOW);
rt_pin_write(PIN_Motor2_A, PIN_LOW);
rt_pin_write(PIN_Motor2_B, PIN_LOW);
rt_pin_write(PIN_Motor3_A, PIN_LOW);
rt_pin_write(PIN_Motor3_B, PIN_LOW);
rt_pin_write(PIN_Motor4_A, PIN_LOW);
rt_pin_write(PIN_Motor4_B, PIN_LOW);
}
/ 控制小車左走*/
void motor_left(void) {
// 向左加速0.5s
rt_pin_write(PIN_Motor1_A, PIN_LOW);
rt_pin_write(PIN_Motor1_B, PIN_HIGH);
rt_pin_write(PIN_Motor2_A, PIN_HIGH);
rt_pin_write(PIN_Motor2_B, PIN_LOW);
rt_pin_write(PIN_Motor3_A, PIN_HIGH);
rt_pin_write(PIN_Motor3_B, PIN_LOW);
rt_pin_write(PIN_Motor4_A, PIN_LOW);
rt_pin_write(PIN_Motor4_B, PIN_HIGH);
rt_thread_mdelay(1000);
//停下
rt_pin_write(PIN_Motor1_A, PIN_LOW);
rt_pin_write(PIN_Motor1_B, PIN_LOW);
rt_pin_write(PIN_Motor2_A, PIN_LOW);
rt_pin_write(PIN_Motor2_B, PIN_LOW);
rt_pin_write(PIN_Motor3_A, PIN_LOW);
rt_pin_write(PIN_Motor3_B, PIN_LOW);
rt_pin_write(PIN_Motor4_A, PIN_LOW);
rt_pin_write(PIN_Motor4_B, PIN_LOW);
}
/* 控制小車右走 /
void motor_right(void) {
// 向右加速0.5s
rt_pin_write(PIN_Motor1_A, PIN_HIGH);
rt_pin_write(PIN_Motor1_B, PIN_LOW);
rt_pin_write(PIN_Motor2_A, PIN_LOW);
rt_pin_write(PIN_Motor2_B, PIN_HIGH);
rt_pin_write(PIN_Motor3_A, PIN_LOW);
rt_pin_write(PIN_Motor3_B, PIN_HIGH);
rt_pin_write(PIN_Motor4_A, PIN_HIGH);
rt_pin_write(PIN_Motor4_B, PIN_LOW);
rt_thread_mdelay(1000);
//停下
rt_pin_write(PIN_Motor1_A, PIN_LOW);
rt_pin_write(PIN_Motor1_B, PIN_LOW);
rt_pin_write(PIN_Motor2_A, PIN_LOW);
rt_pin_write(PIN_Motor2_B, PIN_LOW);
rt_pin_write(PIN_Motor3_A, PIN_LOW);
rt_pin_write(PIN_Motor3_B, PIN_LOW);
rt_pin_write(PIN_Motor4_A, PIN_LOW);
rt_pin_write(PIN_Motor4_B, PIN_LOW);
}
/ 線程1的入口函數(shù) /
static void thread1_entry(void parameter)
{
rt_pin_mode(PIN_Motor_PA0, PIN_MODE_OUTPUT);
rt_pin_mode(PIN_Motor_PA8, PIN_MODE_OUTPUT);
rt_pin_mode(PIN_Motor_PB15, PIN_MODE_OUTPUT);
rt_pin_mode(PIN_Motor_PB14, PIN_MODE_OUTPUT);
rt_pin_mode(PIN_Motor_PB2, PIN_MODE_OUTPUT);
rt_pin_mode(PIN_Motor_PG6, PIN_MODE_OUTPUT);
rt_pin_mode(PIN_Motor_PG7, PIN_MODE_OUTPUT);
rt_pin_mode(PIN_Motor_PD7, PIN_MODE_OUTPUT);
while (1)
{
/ 線程1采用低優(yōu)先級運行,一直打印計數(shù)值 /
if (strcmp(recv_data, "a") == 0) {
motor_forward();
// rt_kprintf(" data:%s rn",recv_data);
rt_memset(recv_data, 0, strlen(recv_data));
}
else if (strcmp(recv_data, "b") == 0) {
motor_backward();
rt_memset(recv_data, 0, strlen(recv_data));
}
else if (strcmp(recv_data, "c") == 0) {
motor_left();
rt_memset(recv_data, 0, strlen(recv_data));
}
else if (strcmp(recv_data, "d") == 0) {
motor_right();
rt_memset(recv_data, 0, strlen(recv_data));
}
rt_thread_mdelay(500);
}
}
/ 線程1 /
int thread1_sample(void)
{
/ 創(chuàng)建線程1,名稱是thread1,入口是thread1_entry /
tid1 = rt_thread_create("thread1",
thread1_entry, RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
/* 如果獲得線程控制塊,啟動這個線程 /
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
return 0;
}
/ 導(dǎo)出到 msh 命令列表中 */
MSH_CMD_EXPORT(thread1_sample, thread sample);
運行結(jié)果
最后,在完成上面步驟后,我們通過命令行執(zhí)行一下代碼(如下圖)即可完成小車與控制設(shè)備的WIFI連接(下面代碼以小車與智能手機的WIFI連接為例)
評論
查看更多