系列文章目录

提示:
第一章 基于索尼PS4手柄的遥控器双向控制


文章目录

  • 系列文章目录
  • 前言
  • 一、PS手柄是什么?
  • 二、一般如何用PS手柄?
    • 1.案例一
    • 2.常见的使用方法
  • 三、!!!我的解决方案
    • 1.首先要了解PS4与工控机的通信机制--蓝牙
    • 2.让PS4连接上蓝牙
  • 总结

前言

随着人工智能的不断发展,做无人驾驶调试肯定需要一个遥控器来调试,对于价值比较大的无人驾驶车辆会有专业的遥控器控制,但是对于刚入门的小白可能没有那么多机会接触高端无人驾驶设备,这里另辟蹊径用打游戏的手柄进行控制。


提示:以下是本篇文章正文内容,下面案例可供参考

一、PS手柄是什么?

示例:PS系列手柄 是索尼提供的游戏机的手柄,该工具是为了解决游戏玩家设计的。

二、一般如何用PS手柄?

1.案例一

之前我用一个PS3做小车双向控制,优点是通过修改硬件把蓝牙换成了Lora,实现远距离双向互传。我的应用场景之一:可以通过ROS发送相关反馈给手柄,比如震动几下等等,这样在机器人调试过程中可以模拟车辆在ROS或者真实小车发生碰撞的情况下让手柄震动给开发者人员。
同时,手柄会把按键的模拟量和键值数据发送给通过无线传输发送给ROS,进而控制小车。

但是也有美中不足的事情:
1.PS3实在太丑了,,相比PS4
2.PS4多了RGB灯,所以可以反向反馈灯光,PS3则只能反馈震动
3.PS4内部有陀螺仪,但是由于我买的国产的,内部IMU芯片没有焊接,ε=(´ο`*)))唉
4.重要的事情再说一遍,PS4还是比PS3帅啊

2.常见的使用方法

常见使用蓝牙与工控机这里我用的是NUC11,配准是11代i71185G7,16G内存,系统安装的是Ubuntu16.04:

sudo apt-get install jstest-gtk
sudo jstest /dev/input/js0

然后在PS4手柄与工控机连接前后对比/dev/input/下面你会看到多出5个文件,分别是一个js0、event*/event*+1、event*+2和一个mouse,这三个分别对应jstest通过JavaScript解析后的键值,和三个未解析的键值,好像有一个是IMU数据,因为一直在发送数据,但是我的PS4是国产的没有IMU。。。另外一个是鼠标数据,pyPS4Controller 库,然后就是再安装这个库在Ubuntu上开发。

pip install pyPS4Controller优点:不需要额外接收器,成本低直接可以在Linux系统上开发
缺点:1.不灵活 2.很难做到反向控制手柄的灯效和震动等等,很难做ROS与手柄的双向互动,目前只能拿到手柄的键值数据单向控制小车车。

该处使用的url网络请求的数据。


三、!!!我的解决方案

1.首先要了解PS4与工控机的通信机制–蓝牙

蓝牙通讯具有两种工作模式:命令响应工作模式和自动
连接工作模式,在自动连接工作模式下模块又可分为主(Master)、从(Slave)和回环(Loopback)三种工作角色。当模块处于自动连接工作模式时,将自动根据事先设定的方式连接的数据传输。

通过两天的摸索:
1.SPP 规范库(Initialisethesppprofilelib)在第一次配对前需要初始化(这个是蓝牙规范,不需要看懂)
2.—查询设备类为 0x1f1f的蓝牙设备,也是蓝牙规范,为此我拆解了PS4,通过一些设备和方法得到一些信息,PS4的蓝牙芯片是用的是RDA5850的芯片,通过查询数据手册看到这是一个多媒体蓝牙芯片,感觉集成化程度很高啊,不管了我们首先要做的是自己做个蓝牙接收器能够连接上这个PS4,我给出两种方案:
1.单片机+蓝牙模块(双模蓝牙才OK)
4.集成单片机的蓝牙芯片,esp8266或者esp32

2.让PS4连接上蓝牙

在连接蓝牙模块之前我们先连接一次手机,看一下这个PS4的MAC地址是多少我通过一个HC蓝牙助手的安卓app看到的

下面是PS4的反馈代码,用VSCODE就可以开发PS4接受模组了

#include "PS4Controller.h"#include <esp_bt_defs.h>
#include <esp_bt_main.h>extern "C" {#include "ps4.h"
}#define ESP_BD_ADDR_HEX_PTR(addr) \(uint8_t*)addr + 0, (uint8_t*)addr + 1, (uint8_t*)addr + 2, \(uint8_t*)addr + 3, (uint8_t*)addr + 4, (uint8_t*)addr + 5PS4Controller::PS4Controller() {}bool PS4Controller::begin() {ps4SetEventObjectCallback(this, &PS4Controller::_event_callback);ps4SetConnectionObjectCallback(this, &PS4Controller::_connection_callback);if (!btStarted() && !btStart()) {log_e("btStart failed");return false;}esp_bluedroid_status_t btState = esp_bluedroid_get_status();if (btState == ESP_BLUEDROID_STATUS_UNINITIALIZED) {if (esp_bluedroid_init()) {log_e("esp_bluedroid_init failed");return false;}}if (btState != ESP_BLUEDROID_STATUS_ENABLED) {if (esp_bluedroid_enable()) {log_e("esp_bluedroid_enable failed");return false;}}ps4Init();return true;
}#define ESP_BD_ADDR_STR         "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"
bool PS4Controller::begin(const char* mac) {esp_bd_addr_t addr;if (sscanf(mac, ESP_BD_ADDR_STR, ESP_BD_ADDR_HEX_PTR(addr)) != ESP_BD_ADDR_LEN) {log_e("Could not convert %s\n to a MAC address", mac);return false;}ps4SetBluetoothMacAddress(addr);return begin();
}void PS4Controller::end() {}bool PS4Controller::isConnected() { return ps4IsConnected(); }
//下面这个函数是通过上位机发送指令控制PS4手柄的RGB灯颜色的
void PS4Controller::setLed(uint8_t r, uint8_t g, uint8_t b) {output.r = r;output.g = g;output.b = b;
}
//下面这个函数是通过上位机发送指令控制PS4手柄的震动的基础库
void PS4Controller::setRumble(uint8_t small, uint8_t large) {output.smallRumble = small;output.largeRumble = large;
}void PS4Controller::setFlashRate(uint8_t onTime, uint8_t offTime) {output.flashOn = onTime / 10;output.flashOff = offTime / 10;
}void PS4Controller::sendToController() { ps4SetOutput(output); }void PS4Controller::attach(callback_t callback) { _callback_event = callback; }void PS4Controller::attachOnConnect(callback_t callback) {_callback_connect = callback;
}void PS4Controller::attachOnDisconnect(callback_t callback) {_callback_disconnect = callback;
}void PS4Controller::_event_callback(void* object, ps4_t data, ps4_event_t event) {PS4Controller* This = (PS4Controller*)object;memcpy(&This->data, &data, sizeof(ps4_t));memcpy(&This->event, &event, sizeof(ps4_event_t));if (This->_callback_event) {This->_callback_event();}
}void PS4Controller::_connection_callback(void* object, uint8_t isConnected) {PS4Controller* This = (PS4Controller*)object;if (isConnected) {delay(250);  // ToDo: figure out how to know when the channel is free again// so this delay can be removedif (This->_callback_connect) {This->_callback_connect();}}else {if (This->_callback_disconnect) {This->_callback_disconnect();}}
}#if !defined(NO_GLOBAL_INSTANCES)
PS4Controller PS4;
#endif

然后在PS4手柄与工控机连接前后对比/dev/input/下面你会看到多出5个文件,分别是一个js0、event*/event*+1、event*+2和一个mouse,这三个分别对应jstest通过JavaScript解析后的键值,和三个未解析的键值,好像有一个是IMU数据,因为一直在发送数据,但是我的PS4是国产的没有IMU。。。另外一个是鼠标数据,pyPS4Controller 库,然后就是再安装这个库在Ubuntu上开发。

#include "ps4.h"#include <esp_system.h>
#include <string.h>#include "ps4_int.h"/********************************************************************************/
/*                              PS4接受数据的常量部分 */
/********************************************************************************/static const uint8_t hid_cmd_payload_ps4_enable[] = {0x43, 0x02};/********************************************************************************/
/*                        本地变量 */
/********************************************************************************/static ps4_connection_callback_t ps4_connection_cb = NULL;
static ps4_connection_object_callback_t ps4_connection_object_cb = NULL;
static void* ps4_connection_object = NULL;static ps4_event_callback_t ps4_event_cb = NULL;
static ps4_event_object_callback_t ps4_event_object_cb = NULL;
static void* ps4_event_object = NULL;static bool is_active = false;/********************************************************************************/
/*                     下面这些是基础功能 */
/********************************************************************************//*******************************************************************************
**
** Function         ps4Init
**
** Description      初始化蓝牙接受服务,然后连接手柄
**
**
** Returns          void
**
*******************************************************************************/
void ps4Init() {sppInit();ps4_l2cap_init_services();
}/*******************************************************************************
**
** Function         ps4IsConnected
**
** Description      当两个设备之间成功发生握手后返回一个值
**
**
**
** Returns          bool
**
*******************************************************************************/
bool ps4IsConnected() { return is_active; }/*******************************************************************************
**
** Function         ps4Enable
**
** Description      PS4使能后持续发送数据
**
**
**
** Returns          void
**
*******************************************************************************/
void ps4Enable() {uint16_t length = sizeof(hid_cmd_payload_ps4_enable);hid_cmd_t hidCommand;hidCommand.code = hid_cmd_code_set_report | hid_cmd_code_type_feature;hidCommand.identifier = hid_cmd_identifier_ps4_enable;memcpy(hidCommand.data, hid_cmd_payload_ps4_enable, length);ps4_l2cap_send_hid(&hidCommand, length);ps4SetLed(32, 32, 200);
}/*******************************************************************************
**
** Function         ps4Cmd
**
** Description      发送给PS4让其震动或者灯光的控制的命令
**
**
** Returns          void
**
*******************************************************************************/
void ps4Cmd(ps4_cmd_t cmd) {hid_cmd_t hidCommand = {.data = {0x80, 0x00, 0xFF}};uint16_t length = sizeof(hidCommand.data);hidCommand.code = hid_cmd_code_set_report | hid_cmd_code_type_output;hidCommand.identifier = hid_cmd_identifier_ps4_control;hidCommand.data[ps4_control_packet_index_small_rumble] = cmd.smallRumble;  // Small RumblehidCommand.data[ps4_control_packet_index_large_rumble] = cmd.largeRumble;  // Big rumblehidCommand.data[ps4_control_packet_index_red] = cmd.r;    // RedhidCommand.data[ps4_control_packet_index_green] = cmd.g;  // GreenhidCommand.data[ps4_control_packet_index_blue] = cmd.b;   // Blue// Time to flash bright (255 = 2.5 seconds)hidCommand.data[ps4_control_packet_index_flash_on_time] = cmd.flashOn;// Time to flash dark (255 = 2.5 seconds)hidCommand.data[ps4_control_packet_index_flash_off_time] = cmd.flashOff;ps4_l2cap_send_hid(&hidCommand, length);
}/*******************************************************************************
**
** Function         ps4SetLedOnly
**
** Description      设置灯光颜色RGB三原色控制的数据
**
**
** Returns          void
**
*******************************************************************************/
void ps4SetLed(uint8_t r, uint8_t g, uint8_t b) {ps4_cmd_t cmd = {0};cmd.r = r;cmd.g = g;cmd.b = b;ps4Cmd(cmd);
}/*******************************************************************************
**
** Function         ps4SetOutput
**
** Description      设置回调
**
**
** Returns          void
**
*******************************************************************************/
void ps4SetOutput(ps4_cmd_t prevCommand) { ps4Cmd(prevCommand); }/*******************************************************************************
**
** Function         ps4SetConnectionCallback
**
** Description      当PS4发送一次手柄键值给接收机时候,进行一次中断处理的回调
**
**
**
** Returns          void
**
*******************************************************************************/
void ps4SetConnectionCallback(ps4_connection_callback_t cb) {ps4_connection_cb = cb;
}/*******************************************************************************
**
** Function         ps4SetConnectionObjectCallback
**
** Description      当PS4连接的时候进行连接通知回调
**
**
**
** Returns          void
**
*******************************************************************************/
void ps4SetConnectionObjectCallback(void* object, ps4_connection_object_callback_t cb) {ps4_connection_object_cb = cb;ps4_connection_object = object;
}/*******************************************************************************
**
** Function         ps4SetEventCallback
**
** Description      接收PS4的回调事件
**
**
** Returns          void
**
*******************************************************************************/
void ps4SetEventCallback(ps4_event_callback_t cb) { ps4_event_cb = cb; }/*******************************************************************************
**
** Function         ps4SetEventObjectCallback
**
** Description      PS4接受控制事件
**
**
** Returns          void
**
*******************************************************************************/
void ps4SetEventObjectCallback(void* object, ps4_event_object_callback_t cb) {ps4_event_object_cb = cb;ps4_event_object = object;
}/*******************************************************************************
**
** Function         ps4SetBluetoothMacAddress
**
** Description      设置接收机需要连接的PS4手柄位移MAC地址
**
**
** Returns          void
**
*******************************************************************************/
void ps4SetBluetoothMacAddress(const uint8_t* mac) {// The bluetooth MAC address is derived from the base MAC address// https://docs.espressif.com/projects/esp-idf/en/stable/api-reference/system/system.html#mac-addressuint8_t baseMac[6];memcpy(baseMac, mac, 6);baseMac[5] -= 2;esp_base_mac_addr_set(baseMac);
}/********************************************************************************/
/*                     本地化的一些功能 */
/********************************************************************************/void ps4ConnectEvent(uint8_t is_connected) {if (is_connected) {ps4Enable();} else {is_active = false;}
}void ps4PacketEvent(ps4_t ps4, ps4_event_t event) {// Trigger packet event, but if this is the very first packet// after connecting, trigger a connection event insteadif (is_active) {if(ps4_event_cb != NULL) {ps4_event_cb(ps4, event);}if (ps4_event_object_cb != NULL && ps4_event_object != NULL) {ps4_event_object_cb(ps4_event_object, ps4, event);}} else {is_active = true;if(ps4_connection_cb != NULL) {ps4_connection_cb(is_active);}if (ps4_connection_object_cb != NULL && ps4_connection_object != NULL) {ps4_connection_object_cb(ps4_connection_object, is_active);}}
}

等我完成PS4的回环流程后再重新组织架构文章。


总结

提示:这里对文章进行总结:
目的:使用PS4连接小车,可以遥控控制一些开关或者其他,当小车在ROS里发生碰撞会反馈给手柄发生碰撞震动,ROS小车的电量或者一些状态通过PS4的RGB灯光进行反馈,实时可以看得到。
完成度:50%,后面开发完成了再整理一下发出来。
祝大家元旦快乐,2022年元旦。

PS4手柄控制无人驾驶小车车相关推荐

  1. 【一】Donkey Car - 驴车-无人驾驶小车项目与硬件介绍(车身模块、运动模块)

    一.项目介绍 主要以无人驾驶小车的控制实践为目的,整体可分为三个阶段,分别是造车.调车.玩车. 造车--完成无人驾驶小车的设计和制作 调车--让小车动起来 玩车--让小车跑起来 二.造车之硬件介绍 整 ...

  2. arduino 无人驾驶小车_无人驾驶小车的实现也没那么复杂

    无人驾驶小车的实现也没那么复杂​mp.weixin.qq.com 2020-01-02 19:10 本文作者:吴东昱,北京钢铁侠科技深度学习算法工程师,主要研究深度学习.无人驾驶等. 我在观察历届智能 ...

  3. 给你一台小车车,怎么让它自动驾驶起来?

    最近几年,「自动驾驶」这个词经常出现在新闻头条里.人们对这个技术充满了憧憬.好奇,企业也纷纷跟进,不管是传统车企如:奔驰.宝马.奥迪,还是新兴科技公司如:Google.苹果.特斯拉.Uber.三星,都 ...

  4. 科技贡献新力量:无人驾驶清扫车上路

    https://www.toutiao.com/a6645552729341035021/ 一辆外形圆润.与腰同高的无人驾驶清扫车近日现身内蒙古师范大学校园.它沿着路牙一边缓缓行进,一边用前侧两个旋转 ...

  5. 哇靠靠,这也行?零基础DIY无人驾驶小车(三)

    原理: 之前在教程(一)中我们讨论了制作无人驾驶小车的方案,结论是当小车采集到图片之后,通过网络传给笔记本,然后笔记本通过深度学习推理,得出结果,反馈给小车.但是目前通过一些优秀的开源库,将cnn网络 ...

  6. 哇靠靠,这也行?零基础DIY无人驾驶小车(一)

    之前做过一个非常简单粗略版本的无人驾驶小车(点击打开链接).曾经答应过一些朋友出教程的,可是一直没有兑现.现在下定决心要把这个教程写完.而且会重新制作一辆更好的无人驾驶小车(使用标准的4车道,增加其他 ...

  7. 活动报名 | 2017无人驾驶智能车Hackathon挑战赛

    研究无人驾驶的各位童鞋,想不想先让研究成果试试水,跟其他的无人驾驶爱好者们一起交流切磋?12月23日,中关村鼎好大厦,量子位携集智.KITTCAMP,邀请你和你和小伙伴来无人驾驶智能车Hackatho ...

  8. 无人驾驶小车调试笔记(五)-- 命令行通信

            简介:在这一章节中,我们需要安装有相关环境(虚拟机方式为例,需要安装有ROS系统,安装过程请参考无人驾驶虚拟仿真教程第2节)的电脑一台,组装好并经过初始化设置的无人驾驶小车一台,路由器 ...

  9. MJKDZ PS2手柄控制OskarBot小车(一):Arduino串口发送数据

    MJKDZ PS2手柄控制OskarBot小车(一):Arduino串口发送数据 [目录] - 1.无线通信模块设置 - 1.1 设置参数 - 1.2 调试步骤 - 2.按键与通信格式 - 2.1 P ...

最新文章

  1. 2022图机器学习必读的11大研究趋势和方向: 微分方程/子图表示/图谱理论/非对称/动态性/鲁棒性/通用性/强化学习/图量子等...
  2. 用wxpython做ui_wxPython - 如何强制UI刷新?
  3. PowerPoint Storyboarding:Visual Studio 2012 RC带给开发者的秘密杀器
  4. Redis实现分布式Session管理
  5. LeetCode 1498. 满足条件的子序列数目(排序+二分查找+快速幂)
  6. Mybatis整合spring
  7. 阿里云发布时间序列数据库TSDB,关于时序你了解多少?
  8. IDEA 配置-XX:-RestrictContended参数
  9. ai人工智能_相信AI?
  10. 基坑监测日报模板_基坑水平监测日报表
  11. 计算机原理加法指令流程图,加法器电路设计方案汇总(八款模拟电路设计原理详解)...
  12. 域策略(3)——限制用户使用USB移动存储设备
  13. android编程拨号界面,在Android4.0中Contacts拨号盘界面剖析(源码)
  14. php调用pdf虚拟打印机,window_在Win7系统中怎么安装PDF彩色虚拟打印机?,前面说过,Word不能直接将文档 - phpStudy...
  15. Linu常用命令精选
  16. Adobe illustrator/Ai 2019 软件安装包
  17. MFC下载网页简单实现
  18. 上面两点下面一个三角形_一个调和线束的证明
  19. 手机电池电量测试软件,如何查看手机的电池电量以及如何测试电池电量
  20. 推荐一个外国的数据结构在线演示网站

热门文章

  1. 再访《Scratch少儿趣味编程》系列图书作者阿部和广、仓本大资
  2. 一张图片的CSS自适应尺寸圆角方案
  3. linux v4l2架构分析之v4l2_ctrl_handler初始化及添加v4l2_ctrl的过程分析
  4. Java生成Excel同个表格内换行
  5. 一、剪辑行业概述与剪辑工具介绍
  6. 【Python蓝桥杯】印章 共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。
  7. 小小白的Android入门之计算器学习
  8. php slik转wav_node.js安装wx-voice转换silk和mp3
  9. 华为交换机升级包及补丁验证完整性
  10. nginx全局配置文件通解