surveyor slam建图中需要的信息参数-breezyslam的应用

在github中找到一个关于slam入门级别建图的学习,这里简单的梳理一下。


chasis 底盘中可以采集传感器的信息,包括BNO055 的imu信息,还有左右两轮子的转速信息。由于DIY这个slam建图的工程师是在乐高EV3上实现的

并且使用java 开发的,本人java水平有限,而且对乐高接口不熟悉,连猜带蒙写一些理解。

有两个比较重要的类,一个是 MapTracker ,提供 位姿信息,位姿包括当前位姿,目标位姿,位姿差,航向角,目标航向。


public static enum PlanState{NONE, DIRECT, PLAN};
    final static float[] speedMult = {1.0f, 0.75f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
    PoseProvider imuPose;
    Pose deltaPose = new Pose();
    public Pose targetPose = new Pose();
    float heading = 0.0f;
    public float targetSpeed = 0.0f;
    public PlanState planState;


另一个类是 LineFollower  提供 底盘的当前速度,目标速度,加速度值

  protected Chassis chassis;
    protected MapTracker tracker;
    protected float P, I, D;
    protected FollowState state = FollowState.STOPPED;
    protected Thread thread;
    //protected static final float MAX_STEER = 125.0f;
    protected static final float MAX_STEER = 10.0f;
    protected static final long LOOP_TIME = 100;
    protected float curSpeed = 0.0f;
    protected float targetSpeed = curSpeed;
    protected float acceleration = 50.0f;
    protected float outputVal;

有以上两个类生成 StatusTracker,

 public StatusTracker(LineFollowerChassis chassis, LineFollower follower, Pose p, String name, String host, Power batt, SampleProvider ir, MapTracker tracker) throws UnknownHostException, IOException
    {
        this.chassis = chassis;
        this.name = name;
        odom = chassis.getPoseProvider();
        imu = chassis.getIMUPoseProvider();
        battery = batt;
        infraRed = ir;
        this.follower = follower;
        this.tracker = tracker;
        setPose(p);
        sock = new Socket(host, 2446);
        dos = new DataOutputStream(sock.getOutputStream());
        dis = new DataInputStream(sock.getInputStream());
        dos.writeUTF(name);
        Thread thread = new Thread(this);
        thread.setDaemon(true);
        thread.start();
    }


最终通过lidar 捕获一帧一帧的数据 写入log

    public Lidar(Port motorPort, Port sensorPort, RegulatedMotor left, RegulatedMotor right, PoseProvider robotPose, PoseProvider pose2, String logName, StatusTracker status) throws IOException
    {
        System.out.println("Starting Lidar");
        log = new PrintWriter(new FileWriter(logName));
        motor = new EV3LargeRegulatedMotor(motorPort);
        laser = new I2CSensor(sensorPort, ADDRESS, I2CPort.TYPE_HIGHSPEED);
        this.left = left;
        this.right = right;
        this.robotPose = robotPose;//对应的pose,有bno055提供的
        this.robotPose2 = pose2;//对应的pose2
        this.status = status;
        running = true;
        Thread scanThread = new Thread(
                new Runnable() {
                    public void run() {
                        runCaptureScans();
                    }
                }
            );
        Thread processThread = new Thread(
                new Runnable() {
                    public void run() {
                        runProcessScans();
                    }
                }
            );
        scanThread.setDaemon(true);
        scanThread.setPriority(Thread.MAX_PRIORITY);
        processThread.setDaemon(true);
        processThread.start();
        scanThread.start();
    }
最终处理一帧汇总后,

protected void runProcessScans()
    {
        System.out.println("Lidar process thread running");
        while (running)
        {
            LidarScan scan = waitForScan();
            if (scan == null)
            {
                System.err.println("Missing lidar scan");
                break;
            }
            log.print(scan.timestamp*1000 + " " + scanCnt++ + " " + scan.leftTacho + " " + scan.rightTacho + " " + 
                    scan.pose.getX() + " " + scan.pose.getY() + " " + scan.pose.getHeading() + " " +
                    scan.pose2.getX() + " " + scan.pose2.getY() + " " + scan.pose2.getHeading() + 
                        " 0 0 0 0 0 0 0 0 0 0 0 0 0 0");
            int zero = 0;
            for(int i = 0; i < scan.ranges.length; i++)
            {
                log.print(" " + scan.ranges[i]*10);
                if (scan.ranges[i] == 0) zero++;
            }
            /*
            for(int i = 0; i < scan.ranges.length; i++)
            {
               if (scan.poses[i] != null)
                    log.print(" " + scan.poses[i].getX() + " " + scan.poses[i].getY() + " " + scan.poses[i].getHeading());
                else
                    log.print(" 0.0 0.0 0.0");
            }
            */
            log.println();
            //System.out.println("scan " + scanCnt + " missed " + missed + " retry " + retry + " error " + error + " zero " + zero);
            status.setScan(scan);
        }
    }


log.dat 如下

55555555555555555555555558.png


heading 经过了归一化处理。范围在-180 -180 


while (newPose < -180)
                newPose += 360;
              while (newPose > 180)
                newPose -= 360;


微信截图_20210125150716.png


先不用考虑乐高的底层是怎么计算出来的,只要在我们的底盘中能够获取正确的传感器信息,并把这些数据 按照图中的格式写入log中,下一步就可以slam建图了。



sitemap