使用Sphero映射环境,如何获得更好的准确性?

时间:2014-12-09 17:20:34

标签: android collision sphero-api sphero

我开发了一个sphero应用程序,让它可以在房子等环境中旅行。目的是绘制环境图。我设法恢复了位置和碰撞点,但似乎这些碰撞破坏了位置。我认为Sphero遇到障碍时会偏离其路径。有没有人有足够的设置以获得最佳准确度?降低速度?基于其他参数(如方向?)的修正。

这是我的代码,应用可以在https://github.com/scenaristeur/sphero-carto下载:

package orbotix.uisample;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;  
import java.util.ArrayList;
import java.util.Random;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;
import orbotix.robot.app.ColorPickerActivity;
import orbotix.robot.base.CollisionDetectedAsyncData;
import orbotix.robot.base.Robot;
import orbotix.robot.base.CollisionDetectedAsyncData.CollisionPower;
import orbotix.robot.sensor.Acceleration;
import orbotix.robot.sensor.LocatorData;
import orbotix.robot.widgets.CalibrationImageButtonView;
import orbotix.robot.widgets.NoSpheroConnectedView;
import orbotix.robot.widgets.NoSpheroConnectedView.OnConnectButtonClickListener;
import orbotix.robot.widgets.SlideToSleepView;
import orbotix.robot.widgets.joystick.JoystickView;
import orbotix.sphero.CollisionListener;
import orbotix.sphero.ConnectionListener;
import orbotix.sphero.LocatorListener;
import orbotix.sphero.Sphero;
import orbotix.view.calibration.CalibrationView;
import orbotix.view.calibration.ControllerActivity;
import orbotix.view.connection.SpheroConnectionView;


public class UiSampleActivity extends ControllerActivity {
/** ID to start the StartupActivity for result to connect the Robot */
private final static int STARTUP_ACTIVITY = 0;
private static final int BLUETOOTH_ENABLE_REQUEST = 11;
private static final int BLUETOOTH_SETTINGS_REQUEST = 12;

/** ID to start the ColorPickerActivity for result to select a color */
private final static int COLOR_PICKER_ACTIVITY = 1;
private boolean mColorPickerShowing = false;

/** The Robot to control */
private Sphero mRobot;

/** One-Touch Calibration Button */
private CalibrationImageButtonView mCalibrationImageButtonView;

/** Calibration View widget */
private CalibrationView mCalibrationView;

/** Slide to sleep view */
private SlideToSleepView mSlideToSleepView;

/** No Sphero Connected Pop-Up View */
private NoSpheroConnectedView mNoSpheroConnectedView;

/** Sphero Connection View */
private SpheroConnectionView mSpheroConnectionView;

//Colors
private int mRed = 0xff;
private int mGreen = 0xff;
private int mBlue = 0xff;
private float positionX;
private float positionY;
private float velocityX;
private float velocityY;
private String couleur="vert";
private float angle=0f;
private float vitesse=0.6f;
private boolean stop;
private boolean auto;
private int countCollision=0;
private int maxCollision=10;
private float accelX;
private float accelY;
private float powerX;
private float powerY;
private static final String TAG = "OBX-LocatorSmag";
private Point point=new Point();
private ArrayList<Point> points=new ArrayList<Point>();
File repertoire= new File (Environment.getExternalStorageDirectory()+"/smag-sphero");

private LocatorListener mLocatorListener = new LocatorListener() {
    @Override
    public void onLocatorChanged(LocatorData locatorData) {
        Log.d(TAG, locatorData.toString());
        if (locatorData != null) {
            positionX=locatorData.getPositionX();
            positionY=locatorData.getPositionY();
            velocityX=locatorData.getVelocityX();
            velocityY=locatorData.getVelocityY();
            point=new Point(positionX,positionY,velocityX,velocityY,couleur);
            points.add(point);

            if ((auto)&&(Math.abs((velocityX))<.01)&&(Math.abs(velocityY)<.01)){

                chercheDirection();
            }
            //Toast.makeText(UiSampleActivity.this,"X:"+positionX, Toast.LENGTH_SHORT).show();
           // ((TextView) findViewById(R.id.txt_locator_x)).setText(locatorData.getPositionX() + " cm");
           // ((TextView) findViewById(R.id.txt_locator_y)).setText(locatorData.getPositionY() + " cm");
           // ((TextView) findViewById(R.id.txt_locator_vx)).setText(locatorData.getVelocityX() + " cm/s");
           // ((TextView) findViewById(R.id.txt_locator_vy)).setText(locatorData.getVelocityY() + " cm/s");
        }
    }
    };

private BroadcastReceiver mColorChangeReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // update colors
        int red = intent.getIntExtra(ColorPickerActivity.EXTRA_COLOR_RED, 0);
        int green = intent.getIntExtra(ColorPickerActivity.EXTRA_COLOR_GREEN, 0);
        int blue = intent.getIntExtra(ColorPickerActivity.EXTRA_COLOR_BLUE, 0);

        // change the color on the ball
        mRobot.setColor(red, green, blue);
    }
};

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    if (!repertoire.exists()) {
          repertoire.mkdir();
        }

    // Set up the Sphero Connection View
    mSpheroConnectionView = (SpheroConnectionView) findViewById(R.id.sphero_connection_view);

    mSpheroConnectionView.addConnectionListener(new ConnectionListener() {

        @Override
        public void onConnected(Robot robot) {
            // Set Robot
            mRobot = (Sphero) robot; // safe to cast for now
            //Set connected Robot to the Controllers
            setRobot(mRobot);
            //active LocatorListener;
            mRobot.getSensorControl().addLocatorListener(mLocatorListener);
            mRobot.getSensorControl().setRate(5);
            mRobot.getCollisionControl().addCollisionListener(mCollisionListener);
            mRobot.getCollisionControl().startDetection(45, 45, 45, 45, 100);
            // Make sure you let the calibration view knows the robot it should control
            mCalibrationView.setRobot(mRobot);

            // Make connect sphero pop-up invisible if it was previously up
            mNoSpheroConnectedView.setVisibility(View.GONE);
            mNoSpheroConnectedView.switchToConnectButton();
            Toast.makeText(UiSampleActivity.this,"Déplacez Sphéro, cliquez ensuite sur Sleep pour enregistrer le parcours dans /smag-sphero", Toast.LENGTH_SHORT).show();

            if (repertoire.isDirectory()){
                Toast.makeText(UiSampleActivity.this,"positions enregistrées dans /smag-sphero", Toast.LENGTH_SHORT).show();

            }else{
                Toast.makeText(UiSampleActivity.this,"création du repertoire /smag-sphero", Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        public void onConnectionFailed(Robot sphero) {
            // let the SpheroConnectionView handle or hide it and do something here...
        }

        @Override
        public void onDisconnected(Robot sphero) {
            if (points!=null){ecrireFichier();}
            mSpheroConnectionView.startDiscovery();

        }
    });

    //Add the JoystickView as a Controller
    addController((JoystickView) findViewById(R.id.joystick));

    // Add the calibration view
    mCalibrationView = (CalibrationView) findViewById(R.id.calibration_view);

    // Set up sleep view
    mSlideToSleepView = (SlideToSleepView) findViewById(R.id.slide_to_sleep_view);
    mSlideToSleepView.hide();
    // Send ball to sleep after completed widget movement
    mSlideToSleepView.setOnSleepListener(new SlideToSleepView.OnSleepListener() {
        @Override
        public void onSleep() {
            mRobot.sleep(0);
        }
    });

    // Initialize calibrate button view where the calibration circle shows above button
    // This is the default behavior
    mCalibrationImageButtonView = (CalibrationImageButtonView) findViewById(R.id.calibration_image_button);
    mCalibrationImageButtonView.setCalibrationView(mCalibrationView);
    // You can also change the size and location of the calibration views (or you can set it in XML)
    mCalibrationImageButtonView.setRadius(100);
    mCalibrationImageButtonView.setOrientation(CalibrationView.CalibrationCircleLocation.ABOVE);

    // Grab the No Sphero Connected View
    mNoSpheroConnectedView = (NoSpheroConnectedView) findViewById(R.id.no_sphero_connected_view);
    mNoSpheroConnectedView.setOnConnectButtonClickListener(new OnConnectButtonClickListener() {

        @Override
        public void onConnectClick() {
            mSpheroConnectionView.setVisibility(View.VISIBLE);
            mSpheroConnectionView.startDiscovery();
        }

        @Override
        public void onSettingsClick() {
            // Open the Bluetooth Settings Intent
            Intent settingsIntent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
            UiSampleActivity.this.startActivityForResult(settingsIntent, BLUETOOTH_SETTINGS_REQUEST);
        }
    });


}


/** Called when the user comes back to this app */
@Override
protected void onResume() {
    super.onResume();
    if (mColorPickerShowing) {
        mColorPickerShowing = false;
        return;
    }

    Log.d("", "registering Color Change Listener");
    IntentFilter filter = new IntentFilter(ColorPickerActivity.ACTION_COLOR_CHANGE);
    registerReceiver(mColorChangeReceiver, filter);
}

/** Called when the user presses the back or home button */
@Override
protected void onPause() {
    super.onPause();
    if (mColorPickerShowing) return;
ecrireFichier();
    // Disconnect Robot properly
    if (mRobot != null) {
        mRobot.disconnect();
    }
    try {
        unregisterReceiver(mColorChangeReceiver); // many times throws exception on leak
    } catch (Exception e) {
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode == RESULT_OK) {
        if (requestCode == COLOR_PICKER_ACTIVITY) {
            //Get the colors
            mRed = data.getIntExtra(ColorPickerActivity.EXTRA_COLOR_RED, 0xff);
            mGreen = data.getIntExtra(ColorPickerActivity.EXTRA_COLOR_GREEN, 0xff);
            mBlue = data.getIntExtra(ColorPickerActivity.EXTRA_COLOR_BLUE, 0xff);

            //Set the color
            mRobot.setColor(mRed, mGreen, mBlue);
        } else if (requestCode == BLUETOOTH_ENABLE_REQUEST) {
            // User enabled bluetooth, so refresh Sphero list
            mSpheroConnectionView.setVisibility(View.VISIBLE);
            mSpheroConnectionView.startDiscovery();
        }
    } else {
        if (requestCode == STARTUP_ACTIVITY) {
            // Failed to return any robot, so we bring up the no robot connected view
            mNoSpheroConnectedView.setVisibility(View.VISIBLE);
        } else if (requestCode == BLUETOOTH_ENABLE_REQUEST) {

            // User clicked "NO" on bluetooth enable settings screen
            Toast.makeText(UiSampleActivity.this,
                    "Enable Bluetooth to Connect to Sphero", Toast.LENGTH_LONG).show();
        } else if (requestCode == BLUETOOTH_SETTINGS_REQUEST) {
            // User enabled bluetooth, so refresh Sphero list
            mSpheroConnectionView.setVisibility(View.VISIBLE);
            mSpheroConnectionView.startDiscovery();
        }
    }
}

/**
 * When the user clicks the "Color" button, show the ColorPickerActivity
 *
 * @param v The Button clicked
 */
public void onColorClick(View v) {

    mColorPickerShowing = true;
    Intent i = new Intent(this, ColorPickerActivity.class);

    //Tell the ColorPickerActivity which color to have the cursor on.
    i.putExtra(ColorPickerActivity.EXTRA_COLOR_RED, mRed);
    i.putExtra(ColorPickerActivity.EXTRA_COLOR_GREEN, mGreen);
    i.putExtra(ColorPickerActivity.EXTRA_COLOR_BLUE, mBlue);

    startActivityForResult(i, COLOR_PICKER_ACTIVITY);
}

public void onAutoClick(View v) {
    mRobot.setColor(150, 150, 0);
     Toast.makeText(UiSampleActivity.this,"Auto", Toast.LENGTH_SHORT).show();
    // for (int i=0;i<10;i++){
     auto=true;
     mRobot.drive(angle, vitesse);

}

/**
 * When the user clicks the "Sleep" button, show the SlideToSleepView shows
 *
 * @param v The Button clicked
 */
public void onSleepClick(View v) {
    ecrireFichier();
    mSlideToSleepView.show();
}

public void onWriteClick(View v){
    String message= "X :"+positionX+" Y : "+positionY;
     Toast.makeText(UiSampleActivity.this,"Ecriture fichier"+message, Toast.LENGTH_LONG).show();

    /* String NOTES ="info.txt";
     File file = new File(Environment.getExternalStorageDirectory(), NOTES);

     String Info = "Test Text";
     try {
        file.createNewFile();
         FileWriter filewriter = new FileWriter(file,false);
         filewriter.write(Info);
         filewriter.close();
         Toast.makeText(UiSampleActivity.this,"OK", Toast.LENGTH_LONG).show();

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
         Toast.makeText(UiSampleActivity.this,"Ecriture plantée"+message, Toast.LENGTH_LONG).show();

    }*/

}
public void onStopClick(View v) {
    if (mRobot != null) {
        // Stop robot
        stop=true;
        auto=false;
        mRobot.stop();
    }
}


@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    mCalibrationView.interpretMotionEvent(event);
    mSlideToSleepView.interpretMotionEvent(event);
    return super.dispatchTouchEvent(event);
}
private final CollisionListener mCollisionListener = new CollisionListener() {
    public void collisionDetected(CollisionDetectedAsyncData collisionData) {
        mRobot.setColor(200, 0, 0);
        Acceleration acceleration = collisionData.getImpactAcceleration();
        CollisionPower power = collisionData.getImpactPower();
        stop=true;
        accelX=(float) acceleration.x;
        accelY=(float) acceleration.y;
        powerX=power.x;
        powerY=power.y;
        couleur="rouge";
        point=new Point(positionX,positionY,velocityX,velocityY,couleur);
        points.add(point);
        couleur="vert";
        countCollision++;

         Toast.makeText(UiSampleActivity.this,countCollision+" Collision "+angle, Toast.LENGTH_SHORT).show();
         if (auto){
             mRobot.setColor(20,0,0);
chercheDirection();

//mRobot.drive(angle,vitesse);
         }
    /*    // Update the UI with the collision data
        Acceleration acceleration = collisionData.getImpactAcceleration();
        mAccelXValueLabel = (TextView) findViewById(R.id.accel_x_value);
        mAccelXValueLabel.setText("" + acceleration.x);

        mAccelYValueLabel = (TextView) findViewById(R.id.accel_y_value);
        mAccelYValueLabel.setText("" + acceleration.y);

        mAccelZValueLabel = (TextView) findViewById(R.id.accel_z_value);
        mAccelZValueLabel.setText("" + acceleration.z);

        mXAxisCheckBox = (CheckBox) findViewById(R.id.axis_x_checkbox);
        mXAxisCheckBox.setChecked(collisionData.hasImpactXAxis());

        mYAxisCheckBox = (CheckBox) findViewById(R.id.axis_y_checkbox);
        mYAxisCheckBox.setChecked(collisionData.hasImpactYAxis());

        CollisionPower power = collisionData.getImpactPower();
        mPowerXValueLabel = (TextView) findViewById(R.id.power_x_value);
        mPowerXValueLabel.setText("" + power.x);

        mPowerYValueLabel = (TextView) findViewById(R.id.power_y_value);
        mPowerYValueLabel.setText("" + power.y);

        mSpeedValueLabel = (TextView) findViewById(R.id.speed_value);
        mSpeedValueLabel.setText("" + collisionData.getImpactSpeed());

        mTimestampLabel = (TextView) findViewById(R.id.time_stamp_value);
        mTimestampLabel.setText(collisionData.getImpactTimeStamp() + " ms");*/
    }
};


public void chercheDirection(){
    //mRobot.drive(angle, vitesse);

    if((velocityX==0)&&(velocityY==0)){

        mRobot.setColor(0, 0, 20);

    Random rand = new Random();
             float variation = rand.nextFloat();
        /* float sens=rand.nextFloat();
         if (sens>.5){
        angle=angle+(180f*variation);
         }else{
             angle=angle-(180f*variation); 
         }*/
        angle=angle+180f*variation;
        if(angle>=360f){
            angle-=360;
        }
        mRobot.setColor(20,0,0);
        //vitesse=0.2f;
        // Toast.makeText(UiSampleActivity.this,"demi tour "+angle+" "+vitesse, Toast.LENGTH_SHORT).show();

        mRobot.drive(angle,vitesse);
        //vitesse=0.6f;
        try {
            Thread.sleep(250);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        mRobot.setColor(20,20,0);
        mRobot.drive(angle,vitesse);
    }
}

public void ecrireFichier(){
    String message= ""; 

    //ecriture
     String cheminTime ="smag-sphero/Smag-Sphero"+System.currentTimeMillis()+".txt";
    String cheminLast ="smag-sphero/Smag-Sphero-last.txt";
     File file = new File(Environment.getExternalStorageDirectory(), cheminTime);
     File fileLast = new File(Environment.getExternalStorageDirectory(), cheminLast);
     Point dernier=null;
      for (int i=0;i<points.size();i++){
          Point p=points.get(i);
          dernier=p;
          message=message+p.getX()+","+p.getY()+","+p.getVelX()+","+p.getVelY()+","+p.getCouleur()+","+p.getAccelX()+","+p.getAccelY()+","+p.getPowerX()+","+p.getPowerY()+"\n";
      }
      message=message+dernier.getX()+","+dernier.getY()+","+dernier.getVelX()+","+dernier.getVelY()+",bleu,"+dernier.getAccelX()+","+dernier.getAccelY()+","+dernier.getPowerX()+","+dernier.getPowerY()+"\n";
     String Info = message;
     try {
        file.createNewFile();
     FileWriter filewriter = new FileWriter(file,true);
     filewriter.write(Info);
     filewriter.close();

        //pour last
     if (fileLast.exists()){
         fileLast.delete();
         }
        fileLast.createNewFile();
         FileWriter filewriterLast = new FileWriter(fileLast,true);
         filewriterLast.write(Info);
         filewriterLast.close();
         Toast.makeText(UiSampleActivity.this,"OK", Toast.LENGTH_LONG).show();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
     Toast.makeText(UiSampleActivity.this,"Ecriture plantée"+message, Toast.LENGTH_LONG).show();

    }
}
}

1 个答案:

答案 0 :(得分:2)

如果您只想映射环境(地面图)的边界,您可以沿着墙壁行驶

您可以分析imu传感器的滚动值,并在以0.15的功率行驶时使其与左墙保持约35°的距离。

当sphero击中凹角时,速度降至零,你必须向右转,直到他再次移动。

当sphero沿凸角转弯时,滚动值将降至0°或更低。你必须保存这个位置,停止sphero并计算返回到该保存点的方向,然后从那里开始映射。