使用android IOIO和安卓手机制作视频遥控小车(控制灯的开关、实时视频传输、方向控制)

android IOIO是通过安卓手机的USB接口控制的电路板,通过android IOIO可以不需要太多的硬件知识,通过安卓手机转接的IOIO板控制外围设备,配件有纸盒、L298N电机驱动模块、旧手机一部(系统必须在安卓2.3以上(与IOIO的固件有关)),旧手机电池两块,LED灯一组,USB线一根、减速电机带轮子 两个、万向轮一个、杜邦线6根左右就够了
先搭好硬件环境,然后进行安卓代码的编写,以下是代码:
视频传输部分参考了网上的代码
public class SocketCameraActivity extends IOIOActivity implements SurfaceHolder.Callback,
Camera.PreviewCallback{
private SurfaceView mSurfaceview = null; // SurfaceView对象:(视图组件)视频显示
private SurfaceHolder mSurfaceHolder = null; // SurfaceHolder对象:(抽象接口)SurfaceView支持类
private Camera mCamera = null; // Camera对象,相机预览
DigitalOutput left,right,light;
ServerSocket ser_socket;
Socket cli_socket;
private String pUsername="XZY";
private String serverUrl="192.168.1.100";
private int serverPort=8888;
private int VideoPreRate=1;
private int tempPreRate=0;
private int VideoQuality=85;
private float VideoWidthRatio=1;
private float VideoHeightRatio=1;
private int VideoWidth=320;
private int VideoHeight=240;
private int VideoFormatIndex=0;
private boolean startSendVideo=false;
private boolean connectedServer=false;
private Button myBtn01, myBtn02;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//禁止屏幕休眠
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
mSurfaceview = (SurfaceView) findViewById(R.id.camera_preview);
myBtn01=(Button)findViewById(R.id.button1);
myBtn02=(Button)findViewById(R.id.button2);
ServerThread st=new ServerThread();
st.start();
//开始连接主机按钮
myBtn01.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
//Common.SetGPSConnected(LoginActivity.this, false);
if(connectedServer){//停止连接主机,同时断开传输
startSendVideo=false;
connectedServer=false;
myBtn02.setEnabled(false);
myBtn01.setText("开始连接");
myBtn02.setText("开始传输");
//断开连接
Thread th = new MySendCommondThread("PHONEDISCONNECT|"+pUsername+"|");
th.start();
}
else//连接主机
{
//启用线程发送命令PHONECONNECT
Thread th = new MySendCommondThread("PHONECONNECT|"+pUsername+"|");
th.start();
connectedServer=true;
myBtn02.setEnabled(true);
myBtn01.setText("停止连接");
}
}});
myBtn02.setEnabled(false);
myBtn02.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
if(startSendVideo)//停止传输视频
{
startSendVideo=false;
myBtn02.setText("开始传输");
}
else{ // 开始传输视频
startSendVideo=true;
myBtn02.setText("停止传输");
}
}});
}
@Override
public void onStart()//重新启动的时候
{
mSurfaceHolder = mSurfaceview.getHolder(); // 绑定SurfaceView,取得SurfaceHolder对象
mSurfaceHolder.addCallback(this); // SurfaceHolder加入回调接口
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// 设置显示器类型,setType必须设置
//读取配置文件
SharedPreferences preParas = PreferenceManager.getDefaultSharedPreferences(SocketCameraActivity.this);
pUsername=preParas.getString("Username", "XZY");
serverUrl=preParas.getString("ServerUrl", "172.17.95.1");
String tempStr=preParas.getString("ServerPort", "8888");
serverPort=Integer.parseInt(tempStr);
tempStr=preParas.getString("VideoPreRate", "1");
VideoPreRate=Integer.parseInt(tempStr);
tempStr=preParas.getString("VideoQuality", "85");
VideoQuality=Integer.parseInt(tempStr);
tempStr=preParas.getString("VideoWidthRatio", "100");
VideoWidthRatio=Integer.parseInt(tempStr);
tempStr=preParas.getString("VideoHeightRatio", "100");
VideoHeightRatio=Integer.parseInt(tempStr);
VideoWidthRatio=VideoWidthRatio/100f;
VideoHeightRatio=VideoHeightRatio/100f;
super.onStart();
}
@Override
protected void onResume() {
super.onResume();
InitCamera();
}
private void InitCamera(){
try{
mCamera = Camera.open();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onPause() {
super.onPause();
try{
if (mCamera != null) {
mCamera.setPreviewCallback(null); // !!这个必须在前,不然退出出错
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
if (mCamera == null) {
return;
}
mCamera.stopPreview();
mCamera.setPreviewCallback(this);
mCamera.setDisplayOrientation(90); //设置横行录制
//获取摄像头参数
Camera.Parameters parameters = mCamera.getParameters();
Size size = parameters.getPreviewSize();
VideoWidth=size.width;
VideoHeight=size.height;
VideoFormatIndex=parameters.getPreviewFormat();
mCamera.startPreview();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
if (null != mCamera) {
mCamera.setPreviewCallback(null); // !!这个必须在前,不然退出出错
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
//如果没有指令传输视频,就先不传
if(!startSendVideo)
return;
if(tempPreRate
tempPreRate++;
return;
}
tempPreRate=0;
try {
if(data!=null)
{
Log.d("YuvImage","success");
YuvImage image = new YuvImage(data,VideoFormatIndex, VideoWidth, VideoHeight,null);
if(image!=null)
{
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
//在此设置图片的尺寸和质量
image.compressToJpeg(new Rect(0, 0, (int)(VideoWidthRatio*VideoWidth),
(int)(VideoHeightRatio*VideoHeight)), VideoQuality, outstream);
outstream.flush();
//启用线程将图像数据发送出去
Thread th = new MySendFileThread(outstream,pUsername,serverUrl,serverPort);
th.start();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public boolean onCreateOptionsMenu(Menu menu)
{
menu.add(0,0,0,"系统设置");
menu.add(0,1,1,"关于程序");
menu.add(0,2,2,"退出程序");
return super.onCreateOptionsMenu(menu);
}
public boolean onOptionsItemSelected(MenuItem item)
{
super.onOptionsItemSelected(item);//获取菜单
switch(item.getItemId())//菜单序号
{
case 0:
//系统设置
{
Intent intent=new Intent(this,SettingActivity.class);
startActivity(intent);
}
break;
case 1://关于程序
{
new AlertDialog.Builder(this)
.setTitle("关于本程序")
.setMessage("遥控小车程序")
.setPositiveButton
(
"我知道了",
new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
}
}
)
.show();
}
break;
case 2://退出程序
{
//杀掉线程强制退出
android.os.Process.killProcess(android.os.Process.myPid());
}
break;
}
return true;
}
class MySendCommondThread extends Thread{
private String commond;
public MySendCommondThread(String commond){
this.commond=commond;
}
public void run(){
//实例化Socket
try {
Socket socket=new Socket(serverUrl,serverPort);
PrintWriter out = new PrintWriter(socket.getOutputStream());
out.println(commond);
out.flush();
} catch (UnknownHostException e) {
} catch (IOException e) {
}
}
}
class MySendFileThread extends Thread{
private String username;
private String ipname;
private int port;
private byte byteBuffer[] = new byte[1024];
private OutputStream outsocket;
private ByteArrayOutputStream myoutputstream;
public MySendFileThread(ByteArrayOutputStream myoutputstream,String username,String ipname,int port){
this.myoutputstream = myoutputstream;
this.username=username;
this.ipname = ipname;
this.port=port;
try {
myoutputstream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
try{
//将图像数据通过Socket发送出去
Socket tempSocket = new Socket(ipname, port);
outsocket = tempSocket.getOutputStream();
//写入头部数据信息
String msg=java.net.URLEncoder.encode("PHONEVIDEO|"+username+"|","utf-8");
byte[] buffer= msg.getBytes();
outsocket.write(buffer);
ByteArrayInputStream inputstream = new ByteArrayInputStream(myoutputstream.toByteArray());
int amount;
while ((amount = inputstream.read(byteBuffer)) != -1) {
outsocket.write(byteBuffer, 0, amount);
}
myoutputstream.flush();
myoutputstream.close();
tempSocket.close();
Log.d("MySendFileThread","success");
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Looper extends BaseIOIOLooper {
@Override
protected void setup() throws ConnectionLostException {
left=ioio_.openDigitalOutput(1);
right=ioio_.openDigitalOutput(2);
light=ioio_.openDigitalOutput(3);
left.write(true);
right.write(true);
light.write(true);
}
@Override
public void loop() throws ConnectionLostException {
}
}
@Override
protected IOIOLooper createIOIOLooper() {
return new Looper();
}
public void go()
{
try {
left.write(false);
right.write(false);
} catch (ConnectionLostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void nstop()
{
try {
left.write(true);
right.write(true);
} catch (ConnectionLostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void goleft()
{
try {
left.write(false);
right.write(true);
} catch (ConnectionLostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void goright()
{
try {
left.write(true);
right.write(false);
} catch (ConnectionLostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void lightOn()
{
try {
light.write(false);
} catch (ConnectionLostException e) {
e.printStackTrace();
}
}
public void lightOff()
{
try {
light.write(true);
} catch (ConnectionLostException e) {
e.printStackTrace();
}
}
class ServerThread extends Thread
{
public void run()
{
try {
ser_socket=new ServerSocket(8000);
} catch (IOException e) {
e.printStackTrace();
}
while (true)
{
try {
cli_socket = ser_socket.accept();
Log.e("接受连接", "accept");
BufferedReader in = new BufferedReader(new InputStreamReader(cli_socket.getInputStream()));
String str ="";
String temp;
while((temp=in.readLine())!=null)
{
str=str+temp;
Log.e("收到数据",temp);
if(temp.equals("lightOn"))
{
Log.d("收到","lightOn");
lightOn();
}
if(temp.equals("lightOff"))
{
lightOff();
}
if(temp.equals("go"))
{
go();
}
if(temp.equals("nstop"))
{
nstop();
}
if(temp.equals("goleft"))
{
goleft();
}
if(temp.equals("goright"))
{
goright();
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
try
{
cli_socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}
}