#简介
接上篇ROS与Android的窃窃私语,很多同学表示
就给几张图和APK的下载连接,然并卵,劳资要知其所以然!
这几天忙着整理代码,准备着自己的第一个开源项目
同学,代码拿走,记得点赞,查看代码请移步RosClient
#建立连接
这么简单我就不解释了吧
|
|
ROSBridgeClient为通信的连接对象,后续的所有功能都依赖于它,所以为了能在所有Activity中使用,保存在Application中,另外断开连接放在了Application中的onTerminate()中,此方法在应用完全退出后,会被调用
#枚举信息
比连接代码还简单
|
|
通过ROSBridgeClient的三个方法分别获取到Node list,Service list,Topic list,然后绑到列表上去
#各种操作
参数枚举
大部分Service的调用和Topick的发布都是带参数的,所以我们需要知道他们的参数列表,对于不是基本参数类型(string,bool,number),我们还需要知道它是由哪些字段组成的
123456789101112131415161718192021222324252627282930313233343536373839try {//获取参数列表,包含了该Topic或Service所有参数信息if(detailType.equalsIgnoreCase("topic")) {typeDef = client.getTopicMessageList(detailName);} else if(detailType.equalsIgnoreCase("service")) {....typeDef = client.getServiceRequestList(detailName);}root = TreeNode.root();//生成参数列表树控件genParamTree(root, typeDef[0]);AndroidTreeView tView = new AndroidTreeView(this, root);paramContainer.addView(tView.getView());} catch (InterruptedException e) {e.printStackTrace();}private void genParamTree(TreeNode parent, TypeDef type) {for (int i = 0; i < type.fieldtypes.length; i++) {if(type.fieldtypes[i].contains("/")) {//Not basic typefor (TypeDef t : typeDef) {//set child for all fieldsif (t.type.equals(type.fieldtypes[i])) {TreeNode node = new TreeNode(new TreeViewHolder.TreeItem(type.fieldnames[i],type.fieldtypes[i],false)).setViewHolder(new TreeViewHolder(this));//非基本类型参数则递归调用genParamTree(node, t);parent.addChild(node);break;}}} else {//Basic typeTreeNode node = new TreeNode(new TreeViewHolder.TreeItem(type.fieldnames[i],type.fieldtypes[i],true)).setViewHolder(new TreeViewHolder(this));parent.addChild(node);}}}生成调用参数数据
遍历上面的参数控件树,拼接调用所需的参数数据
|
|
运动控制
针对Topic /cmd_vel,做一个手势滑动的处理,依然很easy
123456789101112131415161718192021222324252627282930313233343536373839404142434445private void processMoveTopic() {timer = new Timer();TimerTask timerTask = new TimerTask() {public void run() {if (moving) {client.send("{\"op\":\"publish\",\"topic\":\"/cmd_vel\",\"msg\":{\"linear\":{\"x\":" + linearX + ",\"y\":0,\"z\":0},\"angular\":{\"x\":0,\"y\":0,\"z\":" + angularZ + "}}}");Log.d(TAG,"send cmd_vel msg:x:" + linearX + " z:" + angularZ);}}};timer.schedule(timerTask, 1000, 600);tvLog.setOnTouchListener(new View.OnTouchListener() {public boolean onTouch(View view, MotionEvent motionEvent) {switch (motionEvent.getAction()) {case MotionEvent.ACTION_DOWN:moving = true;break;case MotionEvent.ACTION_MOVE:float x = motionEvent.getX();float y = motionEvent.getY();int width = view.getWidth();int height = view.getHeight();float mx = (x - (width / 2f));float my = (height / 2f - y);if(Math.abs(mx) > Math.abs(my)) {angularZ = - mx / (width / 2f) / 0.5f;//Max 0.5} else {linearX = my / (height / 2f) / 0.5f;//Max 0.5}break;case MotionEvent.ACTION_UP:moving = false;linearX = 0;angularZ = 0;break;}return true;}});}地图展示
针对接收到来自于 /map Topic的数据,做展示处理,rviz您肯定用过
12345678910111213141516171819202122232425262728293031323334353637383940public void parseMapTopic(PublishEvent event) {try {JSONParser parser = new JSONParser();JSONObject jsonObj = (JSONObject) parser.parse(event.msg);JSONArray dataArray = (JSONArray)jsonObj.get("data");JSONObject jsonInfo = (JSONObject)jsonObj.get("info");int width = (int)(long)jsonInfo.get("width");int height = (int)(long)jsonInfo.get("height");//原理简单来说就是将data字段当作位图数据来生成图片,color请自便final Bitmap bitmap = Bitmap.createBitmap(width,height, Bitmap.Config.RGB_565);int len = dataArray.size();int x, y, d, p;for(int i = 0; i< len; i++) {x = i % width;y = i / width;d = (int)(long)dataArray.get(i);if(d == -1) {bitmap.setPixel(x, y, Color.rgb(0x59, 0x59, 0x59));} else {p = 0x59 + (int)((0xB1 - 0x59) * d / 100f);bitmap.setPixel(x, y, Color.rgb(p,p,p));}}runOnUiThread(new Runnable() {public void run() {tvLog.setBackground(new BitmapDrawable(getResources(),bitmap));tvLog.setText(tvLog.getText() + "Received map,set to background\n");}});return;} catch (Exception e) {e.printStackTrace();}}
#后续功能
- 通过蓝牙通信传递连接所需IP及端口信息,连接过程自动化
- SLAM相关,包括不限与tf展示,发布目标点…
- ROS与Android上层应用的交互,如接打电话,收发短信…