system: [SYSTEM]

user: 3. 系统开发与实现 3.1. Android端开发实现 本文基于Android系统开发终端平台 [ 12 ]，设备选用Android端智能手机。逻辑上由发布命令模块、查询结果模块、历史记录模块、HTTP通信模块。 Android端主要功能有登录登出注册、发布命令、查询结果、历史记录等。 发布命令模块：此界面为app的主界面，主界面效果如图2所示由登录成功后跳转进入，集成百度语音识别，用来讲用户的语音命令转化为文本，使命令的发布更加简单，除去繁琐的打字功能 [ 13 ]。发布命令的主界面中放置了spinner控件，实时刷新，点击后显示在线的机器人列表，供用户选择使用。在选择机器人时判断机器人是否为闲置状态，防止不同用户控制同一个机器人的问题。Textview用来显示语音转化的文字，如与用户本意不同可再次识别更改。所有数据选择齐全点击发布按钮一个发布命令的流程就执行完毕了。当用户不需要再次使用机器人时可以点击右上角的toolbar控件释放被占用的机器人，这时其他用户才可以使用这个机器人。向右滑动主页面的左侧会显示菜单栏，点击里面的列表可以跳转到相应的模块。 查询结果模块：当发布完任务时界面会跳转到查询界面。该界面显示9个文本框用来显示任务的各项具体信息。当任务状态为“F”停止刷新网络请求，通知栏提示用户机器人任务完成。如果发送任务请求时为关于图片的任务，获取到图片地址后可查看大图，长按图片选择是否保存到本地。 图2. Android端主界面 历史记录模块：由发布命令模块的菜单栏进入，该模块由一个Listview控件，每个item中有四个Textview控件，分别显示用户、机器人、任务描述以及时间。Listview分批量加载，每次加载20个提高加载速度。 HTTP通信模块：该模块负责从服务器获取机器人状态、任务状态以及向服务器发送数据请求等。使用Android中的okhttp框架，通过使用post、get，put不同的方法发送登录时的用户名到各个服务器地址来实现不同的数据请求。 3.2. 服务器端实现 3.2.1. 主要数据模块 系统采用Django + restframework框架进行开发，篇幅限制，这里简要介绍云机器人平台的主要数据模块，有用户数据和任务数据。前者主要对用户基本信息已经行为信息进行记录，形成用户资源库，方便云平台随时进行查询；后者对每个被发布的任务详细信息进行描述，在任务的执行状态与完结状态中扮演着重要角色。 用户数据模块中，考虑到云机器人平台控制端用户与传统网站用户的差异，原有的Django中的用户不能满足本平台的需求，所以需要继承Django内部的抽象用户类，重写用户模块。将发布命令的控制者和接受命令的执行者都看作用户，与重写好的用户类建立一对一连接，在该类的基础上加入两种用户不同的特性。当然，应用中还设有一类管理数据信息的超级用户，这里不详细讨论。用户模块数据信息类图如图3所示。 图3. 用户模块数据信息类图 考虑到后期用户数量的增多，任务执行过程中可能需要反复查询用户信息，如果用户表单占用系统资源过多，可能会影响系统的整体性能，所以将任务等待与任务执行过程中需要的信息分离出来，构建用户状态表如图4所示。 图4. 用户状态类图 任务管理表是整个数据系统的核心，任务的重要数据都存储在管理表中，任务类图如图5所示。控制端用户id和执行端用户id都存储在任务管理表中，通过用户id可以查询用户表和状态表。任务描述为控制端用户上传的用户上传任务的信息，云平台主要对任务描述进行解析。 图5. 任务类图 3.2.2. 用户注册登录部分 安卓端注册方法为访问注册url并将注册信息以表单的形式填入，POST到服务器端。 服务器返回注册结果。 注册发送的信息如下： “username”: “user1”， “password”: “mypassword”， “equipment_type”: “android”， “……”， 注册成功：返回状态码200。 注册失败：返回状态码404。 安卓端登录方法访问登录url并将账号以及密码以Json字符串的形式填入，POST到服务器端。 服务器收到登录请求后查询数据库，验证登陆信息，若登录成功，返回user_id，否则返回错误信息，若返回user_id，安卓端用户需要将该ID存在本地，在任务发送过程中填入url。登录成功后在控制端状态表结构(CommandUserStatus)中增加一个条目。 登录发送的信息如下： “username”: “user1”， “password”: “mypassword”， 登录成功：返回状态码200，并获取user_id。 登录失败：返回状态码404。 ROS机器人注册用户过程与安卓端用户注册大致相同相同，不过增加了机器人本体相关功能的描述。 3.2.3. ROS机器人登录过程 访问登录url并将账号以及密码以表单的形式填入，POST到服务器端。服务器收到登录请求后查询数据库，验证登陆信息，若登录成功，返回user_id，否则返回错误信息，若返回user_id，机器人端用户需要将该ID存在本地，在任务查询过程中填入url。登录成功后执行端状态表结构(ExecuteUserStatus)中增加一个条目。 登录信息： “username”: “robotuser1”， “password”: “mypassword”， 登录成功： 返回状态码200，并获取robot_user_id。 登录失败： 返回状态码404。 3.2.4. 任务发送过程 安卓控制端用户登陆后将语音转化成字符串，配合自身的控制端ID，选择的执行端ID，访问服务器为本用户分配的url，以表单的形式POST任务信息。服务器返回接收命令结果，并决定是否创建任务。 任务发送信息如下： “command_id”: “1”， “execute_id”: “1”， “command”: “command_string”， 服务器创建任务成功：返回状态码200。 服务器创建任务失败：返回状态码404。 任务查询过程： 安卓端用户发布任务到服务器后，查询控制端任务状态表。 任务成功完成后，如执行的任务有拍照功能，安卓端需要解析Json字符串后访问图片的url来显示结果图片。 3.2.5. ROS机器人查询任务 ROS机器人根据服务器分配的robot_user_id访问特定的url，来查询自己当前任务ID。 服务器在相应的url中返回机器人当前状态表。解析出需要的任务以及参数。 “function_task”: “take_picture”， “parameter”: “None”， 机器人返回任务结果： ROS机器人返回执行的结果，结果通过url上传。 若上传成功，status_code为200。 commander发布任务后，查询commander_status得到task_id，根据task_id查询当前任务进度，查看task的内容更新commander_status。 executor查询executor_status是否有任务派送，如果task_id不为空，则说明有任务需要执行，根据task_id查询task，并调用相关function和parameter执行，执行过程中不断查询task并更新task (Update)。 3.3. 机器人端实现 ROS端与服务器通信采用HTTP协议进行通信，ROS的开发中使用了ROS基础的功能包usb_cam和nav_test作为摄像头和移动功能的驱动对功能进行二次开发。 ROS端与服务器通信：ROS端与服务器通信利用Http协议，利用轮询的方式查询任务，查询流程。如图6，在开机自动登录后通过执行者的用户名获取执行者的状态和任务ID (task_id)，在没有任务时任务ID (task_id)为空，服务器接受任务会生成任务ID (task_id)；通过get请求获取task_id后，会通过task_id进入任务页面，在任务页面通过get请求获取任务状态，任务状态为执行状态(Executing)执行任务并使用put请求上传服务器任务需要的数据对任务进行反馈(对上传状态进行监听)。 图6. 机器人端流程 移动机器人ROS端通信：机器人总通信架构如图7。ROS中通过节点(node)与节点之间的通信：包括话题(topic)和服务(service)两种方式。在不需要时效性的通信可以用话题，在机器人的移动过程中需要机器人与控制同步就要用服务。 图7. 机器人通信架构 图像采集模块：图像的采集中基于usb_cam功能包，其中利用了V4L2技术打开摄像头的视频设备，通过数据结构和底层V4L2驱动接口把视频数据记录在内存中保存成一帧一帧的数据，创建视频数据节点/usb_cam/image_raw将视频数据发布，image_view通过订阅视频数据节点/usb_cam/image_raw，利用image_transport、cv_bridge、opencv获取消息(sensor_msg)的图像信息，并将图像保存通过网络通信将图片上传到服务器。 APP控制移动模块：本文中机器人设计是基于APP端控制经服务器人为远程控制机器人，使机器人的移动时刻在用户的控制下，可以增加机器人的可控性方便用户在图像采集等功能时对角度进行控制，要求机器人与服务器时刻保持通信，本文采用轮询的方式更新机器人的移动状态(UP代表前进，DOWN代表后退，LEFT代表左转，RIGHT代表右转，STOP代表停止)，其中利用控制发布节点cmd_vel的线速度(linear_speed)和角速度(angular_speed)达到定义的状态；APP端更新移动状态时，ROS端的移动状态便会改变。 自主避障移动模块：自主避障利用了kinect的深度摄像头生成的点云，其发布的点云通过image_pipeline转换成障碍物栅格分布图。nav_test软件包启动底盘导航程序后会自动处理分析障碍物分布图，之后根据发布的目标的目标导航点自主移动如图8。 图8. 机器人自主避障导航