简介
本项目的主要功能是通过定义星火1号开发板上相应io的电平状态,调试智能手机与星火一号开发板之间的wifi通讯,从而通过手机输入相关的命令,实现对麦克纳姆轮四驱小车的移动控制(如下图所示)
硬件介绍
开发板
使用 rt-thread 星火 1 号 开发板开发本项目,各模块在开发板中位置如图所示
rsapbeery conn
如上图所示,开发板rsapbeery conn中各引脚与对应l298n中输入输出口的对应关系
rw007 wifi
供电方案
八节5号电池串联提供12v电压(两个l298n,两个电池盒共计16个电池):优点是供电较为稳定其,缺点是其重量过大,可能导致小车速度下降。
充电宝3.6v+升压模块升至12v:利用可调输出电压的升压模块可以输出12v电压供l298n使用。但是因为充电宝、升压模块不稳定,其无法稳定输出12v电压,故而舍弃此方案。
接线
接线如上图所示,各个端口所对应具体情况如下:
电源线:+12v接升压模块out+
gnd接升压模块out-
gnd接开发板gnd
+5v接开发板+5v
逻辑控制
对于motor_a(小车前轮的两个电机)和motor_b(小车前轮的两个电机)的控制逻辑如下,其中本项目使用的是pin,因此无需考虑pwm
杜邦线
红色:通常用于连接电源正极或高电平信号。
黑色:通常用于连接电源负极或地线。
蓝色、绿色、黄色等其他颜色:通常用于连接数据线或其他信号线,具体用途取决于具体的电路设计。
小车装配
第一层:电池盒及电池
第二层:星火1号开发板
第三层:l298n电机驱动模块、轮子、电机
软件介绍
wifi 完成初始化
static int i = 0;
int result = rt_eok;
struct rt_wlan_info info;
rt_thread_mdelay(500);
热点扫描
/* 执行扫描 */
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 网络
/ 热点连接 /
log_d(start to connect ap ...);
rt_sem_init(&net_ready, net_ready, 0, rt_ipc_flag_fifo);
/ 注册 wlan ready 回调函数 /
rt_wlan_register_event_handler(rt_wlan_evt_ready, wlan_ready_handler, rt_null);
/ 注册 wlan 断开回调函数 /
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发送数据,rt-studio平台接收数据,数据作为参数传入到电机控制模块
static const char send_data[] = this is tcp client from rt-thread.; /* 发送用到的数据 */
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的入口函数 */
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;
/ 通过函数入口参数url获得host地址(如果是域名,会做域名解析) /
host = gethostbyname(url);
/ 分配用于存放接收数据的缓冲 /
recv_data = rt_malloc(bufsz);
if (recv_data == rt_null)
{
rt_kprintf(no memoryn);
return;
}
/ 创建一个socket,类型是socket_stream,tcp类型 /
if ((sock = socket(af_inet, sock_stream, 0)) == -1)
{
/ 创建socket失败 /
rt_kprintf(socket errorn);
/ 释放接收缓冲 /
rt_free(recv_data);
return;
}
/ 初始化预连接的服务端地址 */
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));
/ 连接到服务端 */
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字节数据 /
bytes_received = recv(sock, recv_data, bufsz - 1, 0);
if (bytes_received < 0)
{
/ 接收失败,关闭这个连接 /
closesocket(sock);
rt_kprintf(nreceived error,close the socket.rn);
/ 释放接收缓冲 /
rt_free(recv_data);
break;
}
else if (bytes_received == 0)
{
/ 默认 recv 为阻塞模式,此时收到0认为连接出错,关闭这个连接 /
closesocket(sock);
rt_kprintf(nreceived error,close the socket.rn);
/ 释放接收缓冲 /
rt_free(recv_data);
break;
}
/ 有接收到数据,把末端清零 /
recv_data[bytes_received] = '�';
if (strncmp(recv_data, q, 1) == 0 || strncmp(recv_data, q, 1) == 0)
{
/ 如果是首字母是q或q,关闭这个连接 /
closesocket(sock);
rt_kprintf(n got a 'q' or 'q',close the socket.rn);
/ 释放接收缓冲 /
rt_free(recv_data);
break;
}
else
{
/ 在控制终端显示收到的数据 /
rt_kprintf(nreceived data = %s , recv_data);
}
/ 发送数据到sock连接 /
ret = send(sock, send_data, strlen(send_data), 0);
if (ret 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
小车行驶控制
通过设置对应io引脚的高低电平,可以控制电机的转动和停止,从而控制小车的前进,后退,左移和右移
/* 控制小车前进 /
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的入口函数 /
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采用低优先级运行,一直打印计数值 /
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)
{
/ 创建线程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;
}
/ 导出到 msh 命令列表中 */
msh_cmd_export(thread1_sample, thread sample);
运行结果
最后,在完成上面步骤后,我们通过命令行执行一下代码(如下图)即可完成小车与控制设备的wifi连接(下面代码以小车与智能手机的wifi连接为例)
SMT发展路程和趋势
用舌头竟然可以控制电脑?奇怪灵感将为人机交互带来哪些可能
今年VR头显总销售量将达710万台,同比增长23.6%
LED灯具保养小技巧
大普通信新推出的高性能PLL芯片,支持任一频率转换及多路输入输出
智能手机与星火一号开发板之间的WIFI通讯设计实现
华为云会议,让云上办公变得简单高效
算法工程师的现状分析:数据质量差,着急死
0glass入选“深圳人工智能百强企业”
共射极放大器的直流分析、交流分析及仿真电路验证
诺基亚与爱立信在5G领域上你更看好谁
VR游戏体验将向着大空间模式发展
NVIDIA Studio开创创意性能的新时代
上拉电阻阻值的选择原则和经验总结
机器学习所负责的任务的分类方法介绍
如何更换直流无刷电机的轴承及注意事项
华为手机今年上半年的全球发货量为1.18亿台增长了24%
新能源汽车进入量价齐升的“白银时代”,银轮股份加大研发投入
基于DSP芯片TMS320VC54lOA实现LCD液晶屏显示的设计方案
三星S7系列横扫韩国 1/4市占,iPhone 7第五