Qt框架下的人工势场法仿真实现

Qt框架下的人工势场法仿真实现

基于Qt框架的人工势场法仿真实现,包含完整的界面和算法核心。

一、项目结构与核心类设计

1. 主程序结构

ArtificialPotentialField/
├── main.cpp              # 程序入口
├── mainwindow.h/cpp     # 主窗口类
├── potentialfield.h/cpp  # 势场计算核心类
├── robot.h/cpp          # 机器人类
├── obstacle.h/cpp       # 障碍物类
├── simulationwidget.h/cpp # 仿真显示部件
└── controlpanel.h/cpp   # 控制面板

2. 核心类定义

potentialfield.h – 势场计算核心

#ifndef POTENTIALFIELD_H
#define POTENTIALFIELD_H

#include <QObject>
#include <QPointF>
#include <QVector>
#include <QDebug>

class PotentialField : public QObject
{
    Q_OBJECT
    
public:
    struct Parameters {
        double k_att = 1.0;      // 引力系数
        double k_rep = 1000.0;   // 斥力系数
        double d0 = 50.0;        // 障碍物影响距离
        double step_size = 5.0;  // 步长
        double goal_tolerance = 5.0; // 目标容差
        int max_iterations = 1000;  // 最大迭代次数
    };
    
    explicit PotentialField(QObject *parent = nullptr);
    
    // 设置参数
    void setParameters(const Parameters &params);
    
    // 路径规划
    QVector<QPointF> planPath(const QPointF &start, 
                              const QPointF &goal, 
                              const QVector<QPointF> &obstacles);
    
    // 计算单个点的合力
    QPointF calculateTotalForce(const QPointF &position, 
                               const QPointF &goal, 
                               const QVector<QPointF> &obstacles);
    
signals:
    void calculationProgress(int percent);
    void pathCalculated(const QVector<QPointF> &path);
    void algorithmFinished(bool success, const QString &message);
    
private:
    // 计算引力
    QPointF calculateAttractiveForce(const QPointF &position, 
                                    const QPointF &goal);
    
    // 计算斥力
    QPointF calculateRepulsiveForce(const QPointF &position, 
                                   const QPointF &obstacle);
    
    // 计算两点距离
    double distance(const QPointF &p1, const QPointF &p2);
    
    Parameters m_params;
};
#endif

potentialfield.cpp – 势场算法实现

#include "potentialfield.h"
#include <cmath>

PotentialField::PotentialField(QObject *parent) 
    : QObject(parent) {}

void PotentialField::setParameters(const Parameters &params) {
    m_params = params;
}

QVector<QPointF> PotentialField::planPath(const QPointF &start, 
                                          const QPointF &goal, 
                                          const QVector<QPointF> &obstacles) {
    QVector<QPointF> path;
    QPointF current = start;
    int iteration = 0;
    
    path.append(current);
    
    while (iteration < m_params.max_iterations) {
        // 检查是否到达目标
        if (distance(current, goal) < m_params.goal_tolerance) {
            path.append(goal);
            emit algorithmFinished(true, "成功到达目标点!");
            emit calculationProgress(100);
            return path;
        }
        
        // 计算合力
        QPointF totalForce = calculateTotalForce(current, goal, obstacles);
        
        // 归一化并移动
        double forceMagnitude = std::sqrt(totalForce.x() * totalForce.x() + 
                                         totalForce.y() * totalForce.y());
        
        if (forceMagnitude > 0) {
            QPointF direction(totalForce.x() / forceMagnitude, 
                             totalForce.y() / forceMagnitude);
            current += direction * m_params.step_size;
        } else {
            // 合力为零,可能陷入局部最小值
            emit algorithmFinished(false, "陷入局部最小值");
            return path;
        }
        
        path.append(current);
        iteration++;
        
        // 更新进度
        int progress = (iteration * 100) / m_params.max_iterations;
        emit calculationProgress(progress);
    }
    
    emit algorithmFinished(false, "达到最大迭代次数");
    return path;
}

QPointF PotentialField::calculateTotalForce(const QPointF &position, 
                                           const QPointF &goal, 
                                           const QVector<QPointF> &obstacles) {
    QPointF attractiveForce = calculateAttractiveForce(position, goal);
    QPointF repulsiveForce(0, 0);
    
    for (const QPointF &obstacle : obstacles) {
        QPointF repForce = calculateRepulsiveForce(position, obstacle);
        repulsiveForce += repForce;
    }
    
    return attractiveForce + repulsiveForce;
}

QPointF PotentialField::calculateAttractiveForce(const QPointF &position, 
                                                const QPointF &goal) {
    double dist = distance(position, goal);
    QPointF direction = goal - position;
    
    if (dist > 0) {
        direction /= dist;
    }
    
    return direction * m_params.k_att * dist;
}

QPointF PotentialField::calculateRepulsiveForce(const QPointF &position, 
                                               const QPointF &obstacle) {
    double dist = distance(position, obstacle);
    
    if (dist > m_params.d0 || dist == 0) {
        return QPointF(0, 0);
    }
    
    QPointF direction = position - obstacle;
    if (dist > 0) {
        direction /= dist;
    }
    
    double forceMagnitude = m_params.k_rep * (1.0/dist - 1.0/m_params.d0) * (1.0/(dist*dist));
    return direction * forceMagnitude;
}

double PotentialField::distance(const QPointF &p1, const QPointF &p2) {
    return std::sqrt((p1.x() - p2.x()) * (p1.x() - p2.x()) + 
                    (p1.y() - p2.y()) * (p1.y() - p2.y()));
}

simulationwidget.h – 仿真显示部件

#ifndef SIMULATIONWIDGET_H
#define SIMULATIONWIDGET_H

#include <QWidget>
#include <QPainter>
#include <QMouseEvent>
#include <QPointF>
#include <QVector>

class SimulationWidget : public QWidget
{
    Q_OBJECT
    
public:
    enum EditMode {
        MODE_START,
        MODE_GOAL,
        MODE_OBSTACLE
    };
    
    explicit SimulationWidget(QWidget *parent = nullptr);
    
    // 设置模式
    void setEditMode(EditMode mode);
    
    // 设置路径
    void setPath(const QVector<QPointF> &path);
    
    // 设置障碍物
    void setObstacles(const QVector<QPointF> &obstacles);
    
    // 获取起点、终点、障碍物
    QPointF getStartPoint() const { return m_startPoint; }
    QPointF getGoalPoint() const { return m_goalPoint; }
    QVector<QPointF> getObstacles() const { return m_obstacles; }
    
    // 清空
    void clearAll();
    void clearPath();
    
signals:
    void environmentChanged();
    
protected:
    void paintEvent(QPaintEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;
    
private:
    void drawRobot(QPainter &painter, const QPointF &position);
    void drawGoal(QPainter &painter, const QPointF &position);
    void drawObstacle(QPainter &painter, const QPointF &position);
    void drawPath(QPainter &painter, const QVector<QPointF> &path);
    
    EditMode m_editMode;
    QPointF m_startPoint;
    QPointF m_goalPoint;
    QVector<QPointF> m_obstacles;
    QVector<QPointF> m_path;
    bool m_showPotentialField;
    
    const int ROBOT_RADIUS = 10;
    const int GOAL_RADIUS = 15;
    const int OBSTACLE_RADIUS = 20;
};
#endif

mainwindow.h – 主窗口

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QThread>
#include "potentialfield.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

// 工作线程类
class PathPlanningThread : public QThread
{
    Q_OBJECT
    
public:
    PathPlanningThread(PotentialField *potentialField, 
                       const QPointF &start, 
                       const QPointF &goal, 
                       const QVector<QPointF> &obstacles,
                       QObject *parent = nullptr)
        : QThread(parent), m_potentialField(potentialField), 
          m_start(start), m_goal(goal), m_obstacles(obstacles) {}
    
protected:
    void run() override {
        QVector<QPointF> path = m_potentialField->planPath(m_start, m_goal, m_obstacles);
        emit pathReady(path);
    }
    
signals:
    void pathReady(const QVector<QPointF> &path);
    
private:
    PotentialField *m_potentialField;
    QPointF m_start;
    QPointF m_goal;
    QVector<QPointF> m_obstacles;
};

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void onStartClicked();
    void onPauseClicked();
    void onResetClicked();
    void onPathCalculated(const QVector<QPointF> &path);
    void onCalculationProgress(int percent);
    void onAlgorithmFinished(bool success, const QString &message);
    
    // 编辑模式切换
    void onSetStartMode();
    void onSetGoalMode();
    void onSetObstacleMode();
    
private:
    Ui::MainWindow *ui;
    PotentialField *m_potentialField;
    PathPlanningThread *m_planningThread;
    bool m_isRunning;
};
#endif

3. UI界面设计 (mainwindow.ui)

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>1200</width>
    <height>800</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>人工势场法路径规划仿真</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QHBoxLayout" name="horizontalLayout">
    <item>
     <widget class="SimulationWidget" name="simulationWidget">
      <property name="minimumSize">
       <size>
        <width>800</width>
        <height>600</height>
       </size>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QGroupBox" name="controlGroupBox">
      <property name="title">
       <string>控制面板</string>
      </property>
      <layout class="QVBoxLayout" name="verticalLayout">
       
       <!-- 参数设置 -->
       <widget class="QGroupBox" name="parametersGroupBox">
        <property name="title">
         <string>势场参数</string>
        </property>
        <layout class="QFormLayout" name="formLayout">
         <item row="0" column="0">
          <widget class="QLabel" name="label">
           <property name="text">
            <string>引力系数:</string>
           </property>
          </widget>
         </item>
         <item row="0" column="1">
          <widget class="QDoubleSpinBox" name="kAttSpinBox">
           <property name="minimum">
            <double>0.100000000000000</double>
           </property>
           <property name="maximum">
            <double>100.000000000000000</double>
           </property>
           <property name="singleStep">
            <double>0.100000000000000</double>
           </property>
           <property name="value">
            <double>1.000000000000000</double>
           </property>
          </widget>
         </item>
         <!-- 类似添加其他参数:斥力系数、影响距离、步长等 -->
        </layout>
       </widget>
       
       <!-- 编辑模式 -->
       <widget class="QGroupBox" name="editModeGroupBox">
        <property name="title">
         <string>编辑模式</string>
        </property>
        <layout class="QVBoxLayout" name="verticalLayout_2">
         <item>
          <widget class="QPushButton" name="setStartButton">
           <property name="text">
            <string>设置起点</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="setGoalButton">
           <property name="text">
            <string>设置终点</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="setObstacleButton">
           <property name="text">
            <string>添加障碍物</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="clearAllButton">
           <property name="text">
            <string>清空所有</string>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
       
       <!-- 控制按钮 -->
       <widget class="QGroupBox" name="controlButtonsGroupBox">
        <property name="title">
         <string>仿真控制</string>
        </property>
        <layout class="QVBoxLayout" name="verticalLayout_3">
         <item>
          <widget class="QPushButton" name="startButton">
           <property name="text">
            <string>开始规划</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="pauseButton">
           <property name="text">
            <string>暂停</string>
           </property>
           <property name="enabled">
            <bool>false</bool>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="resetButton">
           <property name="text">
            <string>重置</string>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
       
       <!-- 进度条 -->
       <widget class="QGroupBox" name="progressGroupBox">
        <property name="title">
         <string>进度</string>
        </property>
        <layout class="QVBoxLayout" name="verticalLayout_4">
         <item>
          <widget class="QProgressBar" name="progressBar">
           <property name="value">
            <number>0</number>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QLabel" name="statusLabel">
           <property name="text">
            <string>就绪</string>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
       
      </layout>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
 <customwidgets>
  <customwidget>
   <class>SimulationWidget</class>
   <extends>QWidget</extends>
   <header>simulationwidget.h</header>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

4. 主程序入口

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

二、编译配置 (CMakeLists.txt)

cmake_minimum_required(VERSION 3.16)
project(ArtificialPotentialField)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

find_package(Qt6 COMPONENTS Core Widgets REQUIRED)

# 添加可执行文件
add_executable(${PROJECT_NAME}
    main.cpp
    mainwindow.cpp
    mainwindow.ui
    potentialfield.cpp
    simulationwidget.cpp
)

# 链接Qt库
target_link_libraries(${PROJECT_NAME} 
    PRIVATE Qt6::Core Qt6::Widgets
)

三、仿真功能说明

1. 核心算法特点

2. 可视化功能

3. 交互功能

参考代码 仿真人工势场法的验证采用C++上的qt框架 www.youwenfan.com/contentcsv/71768.html

四、使用说明

  1. 环境设置

    • 点击"设置起点"按钮,在仿真区域点击设置机器人起点
    • 点击"设置终点"按钮,设置目标点
    • 点击"添加障碍物"按钮,添加障碍物
  2. 参数调整

    • 引力系数:控制目标点的吸引力
    • 斥力系数:控制障碍物的排斥力
    • 影响距离:障碍物斥力的作用范围
    • 步长:机器人每一步的移动距离
  3. 运行仿真

    • 点击"开始规划"启动路径规划
    • 实时观察机器人的运动轨迹
    • 可暂停、重置仿真

五、扩展功能建议

  1. 势场可视化

    • 添加网格显示势场强度
    • 用颜色渐变表示势能大小
    • 绘制力场矢量图
  2. 算法改进

    • 添加虚拟目标点避免局部最小值
    • 实现动态窗口法结合
    • 添加速度势场支持动态障碍物
  3. 数据记录

    • 保存规划路径数据
    • 记录势场参数
    • 导出仿真结果图片

专注于matlab/simulink,电子电路,编程