【笔记】ROSjava-android控制ROS机器人——ROSjava与ROS构建的机器人设计综述

在看文章之前,请确定你已经熟悉了ROS和rosjava,并且具备基本的android开发经验

首先,放上视频:基于SLAM的室内自主导航服务机器人

这个机器人由上网本作为核心,在ubuntu上运行ROS系统,由android端辅助控制。这里主要将android的ROSjava部分,会在以后分篇详述。

第一篇,总体介绍ROSjava-android在这个机器人设计中发挥了怎么样的作用。这个android控制程序有如下功能:英文语音识别,能在脱机状况下语音控制机器人的基本运动;中文语音识别,语音控制并可以布置机器人任务(比如去某地区寻找某物体,和人对话等);最基本的按键控制和舵机控制

【笔记】ROSjava-android控制ROS机器人——ROSjava与ROS构建的机器人设计综述_第1张图片

【笔记】ROSjava-android控制ROS机器人——ROSjava与ROS构建的机器人设计综述_第2张图片【笔记】ROSjava-android控制ROS机器人——ROSjava与ROS构建的机器人设计综述_第3张图片

整个rosjava程序由主程序PocketSphinxROS.java、处理发送命令的dispose.java、IsrActivity.java中文语音识别、R开头的几个英文语音识别文件和Talk开头的几个负责发送各种命令的文件组成。这里就先介绍下PocketSphinxROS.java,为什么取这个名字,因为最开始主要为了开发PocketSphinx英文语音,后来功能增多名字也就没改。

package rosjava.wtf.pocketsphinx.version1;

import java.util.Date;

import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.SeekBar.OnSeekBarChangeListener;

import org.ros.address.InetAddressFactory;
import org.ros.android.MessageCallable;
import org.ros.android.RosActivity;
import org.ros.android.view.RosTextView;
import org.ros.node.NodeConfiguration;
import org.ros.node.NodeMainExecutor;

import rosjava.wtf.pocketsphinx.version1.IsrActivity;
import rosjava.wtf.pocketsphinx.version1.RecognitionListener;
import rosjava.wtf.pocketsphinx.version1.RecognizerTask;
import rosjava.wtf.pocketsphinx.version1.TalkChnString;
import rosjava.wtf.pocketsphinx.version1.TalkEnString;
import rosjava.wtf.pocketsphinx.version1.TalkParam;

import edu.cmu.pocketsphinx.demo.R;

public class PocketSphinxROS extends RosActivity implements OnTouchListener, RecognitionListener {

  private RosTextView rosTextView;
  private TalkParam talker;
  private TalkEnString talkerenstring;
  private TalkChnString talkerchnstring;
  private TalkServo talkerserver;
  private TalkObject talkerobject;
  public Button forward,back,right,left,stop,btn_isr_demo,revive;
  public static boolean send=false,sendenstring=false,sendchnstring=false,sendservo=true,sendobject=false;
  public Handler handler = new Handler(){};
  //servo
  public TextView Value01,Value02;
  public static SeekBar servo1;
  public static SeekBar servo2;
  
  public PocketSphinxROS() {
    // The RosActivity constructor configures the notification title and ticker
    // messages.
    super("Pubsub Tutorial", "Pubsub Tutorial");
  }
//*pocketsphinx***************************************************************************************

  static {
    System.loadLibrary("pocketsphinx_jni");
  }
  /**
   * Recognizer task, which runs in a worker thread.
   */
  RecognizerTask rec;
  /**
   * Thread in which the recognizer task runs.
   */
  Thread rec_thread;
  /**
   * Time at which current recognition started.
   */
  Date start_date;
  /**
   * Number of seconds of speech.
   */
  float speech_dur;
  /**
   * Are we listening?
   */
  boolean listening;
  /**
   * Progress dialog for final recognition.
   */
  ProgressDialog rec_dialog;
  /**
   * Performance counter view.
   */
  static TextView performance_text;
  /**
   * Editable text view.
   */

  public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
      start_date = new Date();
      this.listening = true;
      this.rec.start();
      break;
    case MotionEvent.ACTION_UP:
      if (this.listening) {
        Log.d(getClass().getName(), "Showing Dialog");
        this.rec_dialog = ProgressDialog.show(this, "", "Recognizing speech...", true);
        this.rec_dialog.setCancelable(false);
        this.listening = false;
      }
      this.rec.stop();
      break;
    default:
      ;
    }
    /* Let the button handle its own state */
    return false;
  }
//****************************************************************************************
  @SuppressWarnings("unchecked")
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    rosTextView = (RosTextView) findViewById(R.id.text);
    rosTextView.setTopicName("recognizer/output");
    rosTextView.setMessageType(std_msgs.String._TYPE);
    rosTextView.setMessageToStringCallable(new MessageCallable() {
      @Override
      public String call(std_msgs.String message) {
        return message.getData();
      }
    });
    this.rec = new RecognizerTask();
    this.rec_thread = new Thread(this.rec);
    this.listening = false;
    Button voice = (Button) findViewById(R.id.Voice);
    voice.setOnTouchListener(this);
    performance_text = (TextView) findViewById(R.id.PerformanceText); 
    this.rec.setRecognitionListener(this);
    this.rec_thread.start();
    
    forward = (Button)findViewById(R.id.forward);
    back = (Button)findViewById(R.id.back);
    right = (Button)findViewById(R.id.right);
    left = (Button)findViewById(R.id.left);
    stop = (Button)findViewById(R.id.stop);
    revive = (Button)findViewById(R.id.revive);
    btn_isr_demo=(Button)findViewById(R.id.btn_isr_demo);
    
    Value01 = (TextView)findViewById(R.id.value1);
    Value02 = (TextView)findViewById(R.id.value2);
    final SeekBar servo1 = (SeekBar)findViewById(R.id.servo1); //左右
    final SeekBar servo2 = (SeekBar)findViewById(R.id.servo2); //上下
    servo1.setMax(180);
    servo1.setProgress(73);
    servo2.setMax(150);
    servo2.setProgress(145);
    
    forward.setOnTouchListener(new OnTouchListener(){
        @Override
        public boolean onTouch(View v, MotionEvent event) {
          if (event.getAction() == MotionEvent.ACTION_DOWN)
          {
        	  dispose.control("forward");
			send=true;
          }
          else if(event.getAction() == MotionEvent.ACTION_UP)
          {
        	  send=false;
        	  sendenstring=true;
        	  sendchnstring=true;
          }
         return false;
         }
          });
    back.setOnTouchListener(new OnTouchListener(){
        @Override
        public boolean onTouch(View v, MotionEvent event) {
          if (event.getAction() == MotionEvent.ACTION_DOWN)
          {
        	  dispose.control("back");
			 send=true;
          }
          else if(event.getAction() == MotionEvent.ACTION_UP)
          {
        	  send=false;
        	  sendenstring=true;
        	  sendchnstring=true;
          }
         return false;
         }
          });
    left.setOnTouchListener(new OnTouchListener(){
        @Override
        public boolean onTouch(View v, MotionEvent event) {
          if (event.getAction() == MotionEvent.ACTION_DOWN)
          {
			dispose.control("left");
			send=true;
          }
          else if(event.getAction() == MotionEvent.ACTION_UP)
          {
        	  send=false;
        	  sendenstring=true;
        	  sendchnstring=true;
          }
         return false;
         }
          });
    right.setOnTouchListener(new OnTouchListener(){
        @Override
        public boolean onTouch(View v, MotionEvent event) {
          if (event.getAction() == MotionEvent.ACTION_DOWN)
          {
        	  dispose.control("right");
			send=true;
          }
          else if(event.getAction() == MotionEvent.ACTION_UP)
          {
        	  send=false;
        	  sendenstring=true;
        	  sendchnstring=true;
          }
         return false;
         }
          });
       stop.setOnTouchListener(new OnTouchListener(){
        @Override
        public boolean onTouch(View v, MotionEvent event) {
          if (event.getAction() == MotionEvent.ACTION_DOWN)
          {
        	  dispose.control("stop");
			send = false;				
          }
          else if(event.getAction() == MotionEvent.ACTION_UP)
          {
        	  sendenstring=true;
        	  sendchnstring=true;
          }
         return false;
         }
          });
       btn_isr_demo.setOnTouchListener(new OnTouchListener(){
           @Override
           public boolean onTouch(View v, MotionEvent event) {
             if (event.getAction() == MotionEvent.ACTION_DOWN)
             {
             }
             else if(event.getAction() == MotionEvent.ACTION_UP)
             {
     			Intent intent = new Intent();
     			intent.setClass(PocketSphinxROS.this,IsrActivity.class);
            	 startActivity(intent);
             }
            return false;
            }
             });
       revive.setOnTouchListener(new OnTouchListener(){
           @Override
           public boolean onTouch(View v, MotionEvent event) {
             if (event.getAction() == MotionEvent.ACTION_DOWN)
             {
            	 dispose.control("revive");
             }
             else if(event.getAction() == MotionEvent.ACTION_UP)
             {
           	  send=false;
         	 servo1.setProgress(73);
         	 servo2.setProgress(145);
             }
            return false;
            }
             });
       
       servo1.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){
    	      @Override
    	      public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
    	      {
    	    	  if(progress > 150){
    	    	        Value01.setText("当前角度:" + 0.6 );
    	    	        TalkServo.pos[0]=0.6;
    	    	  }
    	    	  else{
    	    		  Value01.setText("当前角度:" + ((float)(progress-90)/100 ));
    	    		  TalkServo.pos[0]=(float)(progress-90)/100;
    			}
    			sendservo=true;
    	      }
    	      @Override
    	      public void onStartTrackingTouch(SeekBar seekBar)
    	      {
    	      }
    	      @Override
    	      public void onStopTrackingTouch(SeekBar seekBar)
    	      { 
    	      }   	      
    	    });
    	    
    	    servo2.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){
    	      @Override
    	      public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser)
    	      {
    	        Value02.setText("当前角度:" +((float)(progress-75)/100));      	       
    	        TalkServo.pos[1]=(float)(progress-75)/100;
    			sendservo=true;
    	      }
    	      @Override
    	      public void onStartTrackingTouch(SeekBar seekBar)
    	      {
    	      }
    	      @Override
    	      public void onStopTrackingTouch(SeekBar seekBar)
    	      {
    	      }
    	      });
  }
    //Voice Control 
    /** Called when partial results are generated. */
    public void onPartialResults(Bundle b) {
      final String hyp = b.getString("hyp");
      handler.post(new Runnable() {
          public void run() {
            performance_text.setText(hyp);
          }
        });
    }

    /** Called with full results are generated. */
    public void onResults(Bundle b) {
		final String hyp = b.getString("hyp");
		final PocketSphinxROS that = this;
		  handler.post(new Runnable() {
			public void run() {
				performance_text.setText(hyp);
				dispose.control(hyp);
				sendenstring=true;
				send=true;
				Log.d(getClass().getName(), "Hiding Dialog");
				that.rec_dialog.dismiss();
			}
		});
	}

    public void onError(int err) {   
    }   
	@Override
	protected void init(NodeMainExecutor nodeMainExecutor) {
		// TODO Auto-generated method stub
	    talker = new TalkParam();
	    talkerenstring = new TalkEnString();
	    talkerchnstring = new TalkChnString();
	    talkerserver = new TalkServo();
	    talkerobject = new TalkObject();
	     NodeConfiguration nodeConfiguration = NodeConfiguration.newPublic(InetAddressFactory.newNonLoopback().getHostAddress(), getMasterUri());
	     // 这里用户已经被提示输入master的URI来开始或启动本地master
	     nodeConfiguration.setMasterUri(getMasterUri());
	     nodeMainExecutor.execute(talker, nodeConfiguration);
	     nodeMainExecutor.execute(talkerenstring, nodeConfiguration);
	     nodeMainExecutor.execute(talkerchnstring, nodeConfiguration);
	     nodeMainExecutor.execute(talkerserver, nodeConfiguration);
	     nodeMainExecutor.execute(talkerobject, nodeConfiguration);
	     //  RosTextView作为显示输入信息是必须存在的
	     nodeMainExecutor.execute(rosTextView, nodeConfiguration);
	   }	
}
打开程序首先是填写masterURI,告诉rosjava连接到哪个master上。然后进入这个简陋的操作界面。其中有前后左右的基本命令按钮,2个舵机控制滑条,英文识别语音按钮和跳转到中文语音识别activity的按钮。

开发过pocketsphinx语音识别的一定很熟悉其中部分代码,这个是pocketsphinx的固定套路。中文语音我用了讯飞的引擎,联网的状况下效果很好。信息通道建立部分,我建了6个ROS节点,talker(TalkParam)负责发送控制电机的参数命令,使用geometry_msgs/Twist格式。talkerchnstring(TalkChnString)负责发送中文语音识别信息到PC的ROS,使用std_msgs.String._TYPE格式。talkerenstring(TalkEnString)负责发送英文语音识别信息。这里要说明,中文使用讯飞是需要联网才能识别的,而英文pocketsphinx是可以脱机小范围语音识别,用于应对恶劣情况(没网络)。talkerserver(TalkServo)是负责发送控制舵机的命令,使用sensor_msgs/JointState格式。talkerobject(TalkObject)负责把需要寻找的物体名发给机器人,使用std_msgs.String._TYPE格式。这里说明下,我们的机器人具有物体识别能力,通过发送物体名称给机器人,机器人就会明白自己的任务,然后去寻找该物体。

总结,以上代码是由3部分组成:RosActivity中固定格式,包括master连接和节点以及主题的建立;各个功能按键的设定;pocketsphinx英文语音。详细的请看后续文章。



by:season

你可能感兴趣的:(ROS开发)