MSPM0开发学习笔记:二维云台画图(2025电赛 附源代码及引脚配置)
为备战 2025 电赛云台类题目,作者用 MSPM0G3507 搭配 D36A 双通道驱动两颗 42 步进电机,自研三维打印桁架组装二维云台,并分享了当前只做轨迹跟随、尚未挂载激光绘图头时的软硬件连线、引脚映射与画图控制思路。
前言
今年的电赛(2025),很多题都与云台相关,因此为备战电赛,博主这边也是准备了一个由两个42步进电机驱动的云台并提前进行调试,避免赛题出来之后手忙脚乱的,这边的两个42步进电机采用同一个驱动模块进行驱动(D36A),主控肯定采用MSPM0G3507。然后3D打印了一个二维云台的结构并进行组装。本章博客主要是讲这个云台进行绘图的思路以及代码。激光还没有安装上去,目前只是云台的循迹代码
如果无法很好的复现博客里的代码,可以私信作者博取源代码,电赛期间都在线
一、硬件选择
主控:MSPM0G3507
驱动:D36A双路步进电机驱动
电机:42步进电机*2
二、硬件连线
硬件连线部分在上一篇博客里面已经说过了,可以直接去上一篇里面看,这边附上链接
MSPM0开发学习笔记:D36A驱动的42步进电机二维云台(2025电赛 附源代码及引脚配置)
三、软件代码
软件部分采用C语言实现,IDE采用keil,基于逐飞库进行编写
这边先进行一下简单的参数说明,便于理解后面的思路
| 参数 | 含义以及作用 |
|---|---|
| current_x | 目前的X坐标 |
| current_y | 目前的Y坐标 |
| target_x | 需要移动到的X坐标 |
| target_y | 需要移动到的Y坐标 |
| move_x | 需要移动的X距离 |
| move_y | 需要移动的Y距离 |
| point_count | 绘制圆形时候的点数 |
代码实现如下:
函数一:限幅函数
#define MAX_ANGLE_X 1000.0f
#define MIN_ANGLE_X -1000.0f
#define MAX_ANGLE_Y 1000.0f
#define MIN_ANGLE_Y -1000.0f
float limit_angle(float angle, float min, float max) {
if (angle < min) return min;
if (angle > max) return max;
return angle;
}
函数二:激光云台绘制正方形
// Function to draw a square trajectory
// Parameters:
// x_len - length of the square's X-axis dimension
// y_len - length of the square's Y-axis dimension
// MOVE_SPEED - speed of movement between points
void draw_square(int x_len, int y_len, int MOVE_SPEED) {
// Structure to store X and Y angle coordinates
typedef struct {
float x_angle; // X-axis angle position
float y_angle; // Y-axis angle position
} Point;
// Invert Y-axis length (likely for coordinate system adjustment)
y_len = y_len * -1;
// Calculate half-lengths for easier coordinate calculation
float x_len_2 = x_len / 2;
float y_len_2 = y_len / 2;
// Define square vertices relative to origin (0,0)
// Coordinates form a square shape when connected sequentially
Point square_points[] = {
{-1 * x_len_2, y_len_2}, // Top-left corner
{x_len_2, y_len_2}, // Top-right corner
{x_len_2, -1 * y_len_2}, // Bottom-right corner
{-1 * x_len_2, -1 * y_len_2},// Bottom-left corner
{-1 * x_len_2, y_len_2}, // Back to top-left to close the square
{0.0f, 0.0f} // Final point: return to origin
};
// Calculate total number of points in the square trajectory
uint8 point_count = sizeof(square_points) / sizeof(Point);
// Initialize current position at origin (0,0)
float current_x = 0;
float current_y = 0;
// Move to each defined point in sequence
for (uint8 i = 0; i < point_count; i++) {
// Ensure target angles stay within allowed range
float target_x = limit_angle(square_points[i].x_angle, MIN_ANGLE_X, MAX_ANGLE_X);
float target_y = limit_angle(square_points[i].y_angle, MIN_ANGLE_Y, MAX_ANGLE_Y);
// Calculate relative movement from current position to target
float move_x = target_x - current_x;
float move_y = target_y - current_y;
// Update current position to target coordinates
current_x = target_x;
current_y = target_y;
// Send movement command to both axes
d36a_set_angle_both(move_x, move_y, MOVE_SPEED);
// Pause 300ms after reaching each point
system_delay_ms(300);
}
// Pause 2 seconds after completing the square
system_delay_ms(2000);
}
一、函数定义:draw_square函数接收三个参数,分别是正方形的 X 轴长度(x_len)、Y 轴长度(y_len)和移动速度(MOVE_SPEED)。
二、数据结构:定义了Point结构体用于存储坐标点的 X 和 Y 角度值。
三、坐标处理:
1、将 Y 轴长度取负值(为了调整坐标系方向)
2、计算半长(x_len_2, y_len_2),用于确定正方形顶点坐标
3、坐标定义:定义了正方形的 4 个顶点坐标和原点(0,0)坐标以中心点为原点,通过半长计算得出四个顶点位置
4、最后回到一个点 (0,0) 用于回到起点
四、绘制逻辑:
1、遍历所有定义的坐标点
2、对每个目标点进行角度限制(通过limit_angle函数确保在有效范围内)
3、计算当前位置到目标点的移动量
4、调用d36a_set_angle_both函数移动到目标点(同时设置 X 和 Y 方向角度)
5、每个点移动后延迟 300 毫秒,绘制完成后延迟 2000 毫秒
函数三:激光云台绘制圆形
// Function to draw a circle trajectory
// Parameters:
// r - radius of the circle
// MOVE_SPEED - speed of movement between points
// point_count - number of points to use for drawing the circle (more = smoother)
void draw_circle(int r, int MOVE_SPEED, const uint8 point_count) {
// Structure to store X and Y angle coordinates
typedef struct {
float x_angle; // X-axis angle position
float y_angle; // Y-axis angle position
} Point;
// Array to store circle points (extra element to close the loop)
Point circle_points[point_count + 1];
// Calculate coordinates for each point on the circle
for (uint8 i = 0; i < point_count; i++) {
// Convert angle from degrees to radians (full circle = 2π radians)
float rad = 2 * 3.1415926f * i / point_count;
// Calculate X and Y positions using trigonometric functions
// cosine for X-axis, sine for Y-axis to form circular path
circle_points[i].x_angle = r * cosf(rad);
circle_points[i].y_angle = r * sinf(rad);
}
// Close the circle by duplicating the first point as the last point
circle_points[point_count] = circle_points[0];
// Initialize current position at origin (0,0)
float current_x = 0.0f;
float current_y = 0.0f;
// Move to each calculated point in sequence
for (uint8 i = 0; i <= point_count; i++) {
// Ensure target angles stay within allowed range
float target_x = limit_angle(circle_points[i].x_angle, MIN_ANGLE_X, MAX_ANGLE_X);
float target_y = limit_angle(circle_points[i].y_angle, MIN_ANGLE_Y, MAX_ANGLE_Y);
// Calculate relative movement from current position to target
float move_x = target_x - current_x;
float move_y = target_y - current_y;
// Update current position to target
current_x = target_x;
current_y = target_y;
// Send movement command to both axes
d36a_set_angle_both(move_x, move_y, MOVE_SPEED);
// Optional delay between point movements
// system_delay_ms(10);
}
// Return to origin (0,0) after completing the circle
float target_x = 0;
float target_y = 0;
// Calculate movement from last circle point to origin
float move_x = target_x - current_x;
float move_y = target_y - current_y;
// Update current position to origin
current_x = target_x;
current_y = target_y;
// Send final movement command to return to origin
d36a_set_angle_both(move_x, move_y, MOVE_SPEED);
// Pause for 2 seconds after completing the circle
system_delay_ms(2000);
}
通过三角函数(X 轴用余弦、Y 轴用正弦)计算圆周上指定数量的点的坐标,这些点基于圆周的等角度增量分布。函数会按顺序在这些点之间移动(带速度控制),同时确保角度在有效范围内;通过回到第一个点来闭合圆形轨迹,最后返回原点,结束时短暂暂停。点的数量越多,绘制的圆越平滑。
以下是函数中涉及的公式:
-
弧度计算(将圆周等分为指定数量的点)
rad
2 × π × i point_count \text{rad} = 2 \times \pi \times \frac{i}{\text{point\_count}} rad=2×π×point_counti
其中, i i i 为当前点的索引(0 到 point_count-1), point_count \text{point\_count} point_count 为圆周上的总点数, rad \text{rad} rad 为对应角度的弧度值。 -
X轴坐标计算
x _ a n g l e
r × cos ( rad ) x\_angle = r \times \cos(\text{rad}) x_angle=r×cos(rad)
其中, r r r 为圆的半径, cos ( rad ) \cos(\text{rad}) cos(rad) 为弧度对应的余弦值。 -
Y轴坐标计算
y _ a n g l e
r × sin ( rad ) y\_angle = r \times \sin(\text{rad}) y_angle=r×sin(rad)
其中, sin ( rad ) \sin(\text{rad}) sin(rad) 为弧度对应的正弦值。
四、总结
这边给的都是一些简单图形的绘制代码,但是思路都是通用的,复杂图形也可以复用这一套逻辑。大家参考参考就好
如果无法很好的复现博客里的代码,可以私信作者博取源代码,电赛期间都在线
MSPM0開發學習筆記:二維雲臺畫圖(2025電賽 附源代碼及引腳配置)
為備戰 2025 電賽雲臺類題目,作者以 MSPM0G3507 搭配 D36A 雙通道驅動兩顆 42 步進電機,自製 3D 列印桁架組裝二維雲台,並說明目前僅完成軌跡跟隨、尚未安裝雷射頭時的連線、腳位與繪圖控制思路。
來源:https://blog.csdn.net/2403_87969572/article/details/149765767
抓取時間(ISO本地):2026-05-18 05:17:02
文章目錄
前言
今年的電賽(2025),很多題都與雲臺相關,因此為備戰電賽,博主這邊也是準備了一個由兩個42步進電機驅動的雲臺並提前進行調試,避免賽題出來之後手忙腳亂的,這邊的兩個42步進電機採用同一個驅動模塊進行驅動(D36A),主控肯定採用MSPM0G3507。然後3D打印了一個二維雲臺的結構並進行組裝。本章博客主要是講這個雲臺進行繪圖的思路以及代碼。激光還沒有安裝上去,目前只是雲臺的循跡代碼
如果無法很好的復現博客裡的代碼,可以私信作者博取源代碼,電賽期間都在線
一、硬件選擇
主控:MSPM0G3507
驅動:D36A雙路步進電機驅動
電機:42步進電機*2
二、硬件連線
硬件連線部分在上一篇博客裡面已經說過了,可以直接去上一篇裡面看,這邊附上鍊接
MSPM0開發學習筆記:D36A驅動的42步進電機二維雲臺(2025電賽 附源代碼及引腳配置)
三、軟件代碼
軟件部分採用C語言實現,IDE採用keil,基於逐飛庫進行編寫
這邊先進行一下簡單的參數說明,便於理解後面的思路
| 參數 | 含義以及作用 |
|---|---|
| current_x | 目前的X座標 |
| current_y | 目前的Y座標 |
| target_x | 需要移動到的X座標 |
| target_y | 需要移動到的Y座標 |
| move_x | 需要移動的X距離 |
| move_y | 需要移動的Y距離 |
| point_count | 繪製圓形時候的點數 |
代碼實現如下:
函數一:限幅函數
#define MAX_ANGLE_X 1000.0f
#define MIN_ANGLE_X -1000.0f
#define MAX_ANGLE_Y 1000.0f
#define MIN_ANGLE_Y -1000.0f
float limit_angle(float angle, float min, float max) {
if (angle < min) return min;
if (angle > max) return max;
return angle;
}
函數二:激光雲臺繪製正方形
// Function to draw a square trajectory
// Parameters:
// x_len - length of the square's X-axis dimension
// y_len - length of the square's Y-axis dimension
// MOVE_SPEED - speed of movement between points
void draw_square(int x_len, int y_len, int MOVE_SPEED) {
// Structure to store X and Y angle coordinates
typedef struct {
float x_angle; // X-axis angle position
float y_angle; // Y-axis angle position
} Point;
// Invert Y-axis length (likely for coordinate system adjustment)
y_len = y_len * -1;
// Calculate half-lengths for easier coordinate calculation
float x_len_2 = x_len / 2;
float y_len_2 = y_len / 2;
// Define square vertices relative to origin (0,0)
// Coordinates form a square shape when connected sequentially
Point square_points[] = {
{-1 * x_len_2, y_len_2}, // Top-left corner
{x_len_2, y_len_2}, // Top-right corner
{x_len_2, -1 * y_len_2}, // Bottom-right corner
{-1 * x_len_2, -1 * y_len_2},// Bottom-left corner
{-1 * x_len_2, y_len_2}, // Back to top-left to close the square
{0.0f, 0.0f} // Final point: return to origin
};
// Calculate total number of points in the square trajectory
uint8 point_count = sizeof(square_points) / sizeof(Point);
// Initialize current position at origin (0,0)
float current_x = 0;
float current_y = 0;
// Move to each defined point in sequence
for (uint8 i = 0; i < point_count; i++) {
// Ensure target angles stay within allowed range
float target_x = limit_angle(square_points[i].x_angle, MIN_ANGLE_X, MAX_ANGLE_X);
float target_y = limit_angle(square_points[i].y_angle, MIN_ANGLE_Y, MAX_ANGLE_Y);
// Calculate relative movement from current position to target
float move_x = target_x - current_x;
float move_y = target_y - current_y;
// Update current position to target coordinates
current_x = target_x;
current_y = target_y;
// Send movement command to both axes
d36a_set_angle_both(move_x, move_y, MOVE_SPEED);
// Pause 300ms after reaching each point
system_delay_ms(300);
}
// Pause 2 seconds after completing the square
system_delay_ms(2000);
}
一、函數定義:draw_square函數接收三個參數,分別是正方形的 X 軸長度(x_len)、Y 軸長度(y_len)和移動速度(MOVE_SPEED)。
二、數據結構:定義了Point結構體用於存儲座標點的 X 和 Y 角度值。
三、座標處理:
1、將 Y 軸長度取負值(為了調整座標系方向)
2、計算半長(x_len_2, y_len_2),用於確定正方形頂點座標
3、座標定義:定義了正方形的 4 個頂點座標和原點(0,0)座標以中心點為原點,通過半長計算得出四個頂點位置
4、最後回到一個點 (0,0) 用於回到起點
四、繪製邏輯:
1、遍歷所有定義的座標點
2、對每個目標點進行角度限制(通過limit_angle函數確保在有效範圍內)
3、計算當前位置到目標點的移動量
4、調用d36a_set_angle_both函數移動到目標點(同時設置 X 和 Y 方向角度)
5、每個點移動後延遲 300 毫秒,繪製完成後延遲 2000 毫秒
函數三:激光雲臺繪製圓形
// Function to draw a circle trajectory
// Parameters:
// r - radius of the circle
// MOVE_SPEED - speed of movement between points
// point_count - number of points to use for drawing the circle (more = smoother)
void draw_circle(int r, int MOVE_SPEED, const uint8 point_count) {
// Structure to store X and Y angle coordinates
typedef struct {
float x_angle; // X-axis angle position
float y_angle; // Y-axis angle position
} Point;
// Array to store circle points (extra element to close the loop)
Point circle_points[point_count + 1];
// Calculate coordinates for each point on the circle
for (uint8 i = 0; i < point_count; i++) {
// Convert angle from degrees to radians (full circle = 2π radians)
float rad = 2 * 3.1415926f * i / point_count;
// Calculate X and Y positions using trigonometric functions
// cosine for X-axis, sine for Y-axis to form circular path
circle_points[i].x_angle = r * cosf(rad);
circle_points[i].y_angle = r * sinf(rad);
}
// Close the circle by duplicating the first point as the last point
circle_points[point_count] = circle_points[0];
// Initialize current position at origin (0,0)
float current_x = 0.0f;
float current_y = 0.0f;
// Move to each calculated point in sequence
for (uint8 i = 0; i <= point_count; i++) {
// Ensure target angles stay within allowed range
float target_x = limit_angle(circle_points[i].x_angle, MIN_ANGLE_X, MAX_ANGLE_X);
float target_y = limit_angle(circle_points[i].y_angle, MIN_ANGLE_Y, MAX_ANGLE_Y);
// Calculate relative movement from current position to target
float move_x = target_x - current_x;
float move_y = target_y - current_y;
// Update current position to target
current_x = target_x;
current_y = target_y;
// Send movement command to both axes
d36a_set_angle_both(move_x, move_y, MOVE_SPEED);
// Optional delay between point movements
// system_delay_ms(10);
}
// Return to origin (0,0) after completing the circle
float target_x = 0;
float target_y = 0;
// Calculate movement from last circle point to origin
float move_x = target_x - current_x;
float move_y = target_y - current_y;
// Update current position to origin
current_x = target_x;
current_y = target_y;
// Send final movement command to return to origin
d36a_set_angle_both(move_x, move_y, MOVE_SPEED);
// Pause for 2 seconds after completing the circle
system_delay_ms(2000);
}
通過三角函數(X 軸用餘弦、Y 軸用正弦)計算圓周上指定數量的點的座標,這些點基於圓周的等角度增量分佈。函數會按順序在這些點之間移動(帶速度控制),同時確保角度在有效範圍內;通過回到第一個點來閉合圓形軌跡,最後返回原點,結束時短暫暫停。點的數量越多,繪製的圓越平滑。
以下是函數中涉及的公式:
-
弧度計算(將圓周等分為指定數量的點)
rad
2 × π × i point_count \text{rad} = 2 \times \pi \times \frac{i}{\text{point\_count}} rad=2×π×point_counti
其中, i i i 為當前點的索引(0 到 point_count-1), point_count \text{point\_count} point_count 為圓周上的總點數, rad \text{rad} rad 為對應角度的弧度值。 -
X軸座標計算
x _ a n g l e
r × cos ( rad ) x\_angle = r \times \cos(\text{rad}) x_angle=r×cos(rad)
其中, r r r 為圓的半徑, cos ( rad ) \cos(\text{rad}) cos(rad) 為弧度對應的餘弦值。 -
Y軸座標計算
y _ a n g l e
r × sin ( rad ) y\_angle = r \times \sin(\text{rad}) y_angle=r×sin(rad)
其中, sin ( rad ) \sin(\text{rad}) sin(rad) 為弧度對應的正弦值。
四、總結
這邊給的都是一些簡單圖形的繪製代碼,但是思路都是通用的,複雜圖形也可以複用這一套邏輯。大家參考參考就好
如果無法很好的復現博客裡的代碼,可以私信作者博取源代碼,電賽期間都在線
MSPM0开发学习笔记:二维云台画图(2025电赛 附源代码及引脚配置)
The build pairs an MSPM0G3507 MCU with one D36A dual stepper driver powering two NEMA‑17 motors on a printable two‑axis cradle meant for electronics‑contest gimbals; wiring, pinmux, mechanics, and the current firmware that traces paths—even before attaching a laser head—are explained so readers can replicate the rig quickly.
前言
今年的电赛(2025),很多题都与云台相关,因此为备战电赛,博主这边也是准备了一个由两个42步进电机驱动的云台并提前进行调试,避免赛题出来之后手忙脚乱的,这边的两个42步进电机采用同一个驱动模块进行驱动(D36A),主控肯定采用MSPM0G3507。然后3D打印了一个二维云台的结构并进行组装。本章博客主要是讲这个云台进行绘图的思路以及代码。激光还没有安装上去,目前只是云台的循迹代码
如果无法很好的复现博客里的代码,可以私信作者博取源代码,电赛期间都在线
一、硬件选择
主控:MSPM0G3507
驱动:D36A双路步进电机驱动
电机:42步进电机*2
二、硬件连线
硬件连线部分在上一篇博客里面已经说过了,可以直接去上一篇里面看,这边附上链接
MSPM0开发学习笔记:D36A驱动的42步进电机二维云台(2025电赛 附源代码及引脚配置)
三、软件代码
软件部分采用C语言实现,IDE采用keil,基于逐飞库进行编写
这边先进行一下简单的参数说明,便于理解后面的思路
| 参数 | 含义以及作用 |
|---|---|
| current_x | 目前的X坐标 |
| current_y | 目前的Y坐标 |
| target_x | 需要移动到的X坐标 |
| target_y | 需要移动到的Y坐标 |
| move_x | 需要移动的X距离 |
| move_y | 需要移动的Y距离 |
| point_count | 绘制圆形时候的点数 |
代码实现如下:
函数一:限幅函数
#define MAX_ANGLE_X 1000.0f
#define MIN_ANGLE_X -1000.0f
#define MAX_ANGLE_Y 1000.0f
#define MIN_ANGLE_Y -1000.0f
float limit_angle(float angle, float min, float max) {
if (angle < min) return min;
if (angle > max) return max;
return angle;
}
函数二:激光云台绘制正方形
// Function to draw a square trajectory
// Parameters:
// x_len - length of the square's X-axis dimension
// y_len - length of the square's Y-axis dimension
// MOVE_SPEED - speed of movement between points
void draw_square(int x_len, int y_len, int MOVE_SPEED) {
// Structure to store X and Y angle coordinates
typedef struct {
float x_angle; // X-axis angle position
float y_angle; // Y-axis angle position
} Point;
// Invert Y-axis length (likely for coordinate system adjustment)
y_len = y_len * -1;
// Calculate half-lengths for easier coordinate calculation
float x_len_2 = x_len / 2;
float y_len_2 = y_len / 2;
// Define square vertices relative to origin (0,0)
// Coordinates form a square shape when connected sequentially
Point square_points[] = {
{-1 * x_len_2, y_len_2}, // Top-left corner
{x_len_2, y_len_2}, // Top-right corner
{x_len_2, -1 * y_len_2}, // Bottom-right corner
{-1 * x_len_2, -1 * y_len_2},// Bottom-left corner
{-1 * x_len_2, y_len_2}, // Back to top-left to close the square
{0.0f, 0.0f} // Final point: return to origin
};
// Calculate total number of points in the square trajectory
uint8 point_count = sizeof(square_points) / sizeof(Point);
// Initialize current position at origin (0,0)
float current_x = 0;
float current_y = 0;
// Move to each defined point in sequence
for (uint8 i = 0; i < point_count; i++) {
// Ensure target angles stay within allowed range
float target_x = limit_angle(square_points[i].x_angle, MIN_ANGLE_X, MAX_ANGLE_X);
float target_y = limit_angle(square_points[i].y_angle, MIN_ANGLE_Y, MAX_ANGLE_Y);
// Calculate relative movement from current position to target
float move_x = target_x - current_x;
float move_y = target_y - current_y;
// Update current position to target coordinates
current_x = target_x;
current_y = target_y;
// Send movement command to both axes
d36a_set_angle_both(move_x, move_y, MOVE_SPEED);
// Pause 300ms after reaching each point
system_delay_ms(300);
}
// Pause 2 seconds after completing the square
system_delay_ms(2000);
}
一、函数定义:draw_square函数接收三个参数,分别是正方形的 X 轴长度(x_len)、Y 轴长度(y_len)和移动速度(MOVE_SPEED)。
二、数据结构:定义了Point结构体用于存储坐标点的 X 和 Y 角度值。
三、坐标处理:
1、将 Y 轴长度取负值(为了调整坐标系方向)
2、计算半长(x_len_2, y_len_2),用于确定正方形顶点坐标
3、坐标定义:定义了正方形的 4 个顶点坐标和原点(0,0)坐标以中心点为原点,通过半长计算得出四个顶点位置
4、最后回到一个点 (0,0) 用于回到起点
四、绘制逻辑:
1、遍历所有定义的坐标点
2、对每个目标点进行角度限制(通过limit_angle函数确保在有效范围内)
3、计算当前位置到目标点的移动量
4、调用d36a_set_angle_both函数移动到目标点(同时设置 X 和 Y 方向角度)
5、每个点移动后延迟 300 毫秒,绘制完成后延迟 2000 毫秒
函数三:激光云台绘制圆形
// Function to draw a circle trajectory
// Parameters:
// r - radius of the circle
// MOVE_SPEED - speed of movement between points
// point_count - number of points to use for drawing the circle (more = smoother)
void draw_circle(int r, int MOVE_SPEED, const uint8 point_count) {
// Structure to store X and Y angle coordinates
typedef struct {
float x_angle; // X-axis angle position
float y_angle; // Y-axis angle position
} Point;
// Array to store circle points (extra element to close the loop)
Point circle_points[point_count + 1];
// Calculate coordinates for each point on the circle
for (uint8 i = 0; i < point_count; i++) {
// Convert angle from degrees to radians (full circle = 2π radians)
float rad = 2 * 3.1415926f * i / point_count;
// Calculate X and Y positions using trigonometric functions
// cosine for X-axis, sine for Y-axis to form circular path
circle_points[i].x_angle = r * cosf(rad);
circle_points[i].y_angle = r * sinf(rad);
}
// Close the circle by duplicating the first point as the last point
circle_points[point_count] = circle_points[0];
// Initialize current position at origin (0,0)
float current_x = 0.0f;
float current_y = 0.0f;
// Move to each calculated point in sequence
for (uint8 i = 0; i <= point_count; i++) {
// Ensure target angles stay within allowed range
float target_x = limit_angle(circle_points[i].x_angle, MIN_ANGLE_X, MAX_ANGLE_X);
float target_y = limit_angle(circle_points[i].y_angle, MIN_ANGLE_Y, MAX_ANGLE_Y);
// Calculate relative movement from current position to target
float move_x = target_x - current_x;
float move_y = target_y - current_y;
// Update current position to target
current_x = target_x;
current_y = target_y;
// Send movement command to both axes
d36a_set_angle_both(move_x, move_y, MOVE_SPEED);
// Optional delay between point movements
// system_delay_ms(10);
}
// Return to origin (0,0) after completing the circle
float target_x = 0;
float target_y = 0;
// Calculate movement from last circle point to origin
float move_x = target_x - current_x;
float move_y = target_y - current_y;
// Update current position to origin
current_x = target_x;
current_y = target_y;
// Send final movement command to return to origin
d36a_set_angle_both(move_x, move_y, MOVE_SPEED);
// Pause for 2 seconds after completing the circle
system_delay_ms(2000);
}
通过三角函数(X 轴用余弦、Y 轴用正弦)计算圆周上指定数量的点的坐标,这些点基于圆周的等角度增量分布。函数会按顺序在这些点之间移动(带速度控制),同时确保角度在有效范围内;通过回到第一个点来闭合圆形轨迹,最后返回原点,结束时短暂暂停。点的数量越多,绘制的圆越平滑。
以下是函数中涉及的公式:
-
弧度计算(将圆周等分为指定数量的点)
rad
2 × π × i point_count \text{rad} = 2 \times \pi \times \frac{i}{\text{point\_count}} rad=2×π×point_counti
其中, i i i 为当前点的索引(0 到 point_count-1), point_count \text{point\_count} point_count 为圆周上的总点数, rad \text{rad} rad 为对应角度的弧度值。 -
X轴坐标计算
x _ a n g l e
r × cos ( rad ) x\_angle = r \times \cos(\text{rad}) x_angle=r×cos(rad)
其中, r r r 为圆的半径, cos ( rad ) \cos(\text{rad}) cos(rad) 为弧度对应的余弦值。 -
Y轴坐标计算
y _ a n g l e
r × sin ( rad ) y\_angle = r \times \sin(\text{rad}) y_angle=r×sin(rad)
其中, sin ( rad ) \sin(\text{rad}) sin(rad) 为弧度对应的正弦值。
四、总结
这边给的都是一些简单图形的绘制代码,但是思路都是通用的,复杂图形也可以复用这一套逻辑。大家参考参考就好
如果无法很好的复现博客里的代码,可以私信作者博取源代码,电赛期间都在线