此代码的目的是利用电位器来转动伺服电机。当我试图将它插入到程序中时,伺服系统根本没有移动,我不知道这是我的电路板、我的布线还是我的代码的结果。如果有人能在这件事上提供帮助或提供一些帮助,我们将不胜感激。我使用的电路板是一个核心STM L476RG板和电机是一个微型SG90。
#include "mbed.h"
#include "Servo.h"
#include "iostream"
Servo myservo(D6);
AnalogOut MyPot(A1);
int main() {
float PotReading;
PotReading = MyPot.read();
while(1) {
for(int i=0; i<100; i++) {
myservo.SetPosition(PotReading);
wait(0.01);
}
}
}此外,我所使用的代码在已发布的库伺服中具有以下代码: Servo.h
#ifndef MBED_SERVO_H
#define MBED_SERVO_H
#include "mbed.h"
/** Class to control a servo on any pin, without using pwm
*
* Example:
* @code
* // Keep sweeping servo from left to right
* #include "mbed.h"
* #include "Servo.h"
*
* Servo Servo1(p20);
*
* Servo1.Enable(1500,20000);
*
* while(1) {
* for (int pos = 1000; pos < 2000; pos += 25) {
* Servo1.SetPosition(pos);
* wait_ms(20);
* }
* for (int pos = 2000; pos > 1000; pos -= 25) {
* Servo1.SetPosition(pos);
* wait_ms(20);
* }
* }
* @endcode
*/
class Servo {
public:
/** Create a new Servo object on any mbed pin
*
* @param Pin Pin on mbed to connect servo to
*/
Servo(PinName Pin);
/** Change the position of the servo. Position in us
*
* @param NewPos The new value of the servos position (us)
*/
void SetPosition(int NewPos);
/** Enable the servo. Without enabling the servo won't be running. Startposition and period both in us.
*
* @param StartPos The position of the servo to start (us)
* @param Period The time between every pulse. 20000 us = 50 Hz(standard) (us)
*/
void Enable(int StartPos, int Period);
/** Disable the servo. After disabling the servo won't get any signal anymore
*
*/
void Disable();
private:
void StartPulse();
void EndPulse();
int Position;
DigitalOut ServoPin;
Ticker Pulse;
Timeout PulseStop;
};
#endif它还在与它相同的位置上有一个.cpp文件,所以如果有人需要它作为参考,我会把它作为编辑发布。我也会把电线放在以防万一
伺服系统是一个SG90。
电路板的接线:

发布于 2020-05-21 19:18:54
首先要了解的是伺服电机是如何工作的。从数据表中需要一个脉宽为1到2ms的50 to。脉宽决定位置,因此1ms的宽度将使伺服定位在其行程的一端,2ms的脉冲将在另一端设置位置,1.5ms将设置中心位置。
其次,您需要阅读您正在使用的Servo类的文档(在注释中)。它甚至有示例代码。首先您需要实例化一个Servo对象(您已经完成了),然后您需要通过设置它的脉冲间隔和初始脉冲宽度(或位置)来启用它:
Servo output( D6 ) ;
output.Enable( 1500, 20000 ) ; // Centre position, 50Hz然后,如果您想读取模拟输入,显然需要一个AnalogIn对象:
AnalogOut input(A1);然后,您需要理解的是,闭环控制系统必须不断读取其输入,以调整输出。在这里,你只读了一次电位器之前的控制回路,所以在循环中它从不改变值,所以位置不会改变。此外,您有一个完全不必要的内部循环,它来自于一个完全不同的Servo实现这里的示例代码--该示例不是一个闭环控制系统--它只是在整个范围内不停地循环伺服--这不是您在本例中试图实现的,它只是一个货物邪教编程。
在闭环控制中,您可以连续地控制
_______
| |
V |
get-input | <repeat>
set-output |
|_______|最后,您需要理解,在这种情况下,输入度量的单位与输出设置的单位不相同--它们需要缩放,以便将整个输入范围映射到全尺度输出范围。mbed AnalogIn类有两个读取函数;AnalogIn::read()在0.0-1.0范围内返回一个float,AnalogIn::read_u16返回一个uint16_t值0到65535。就我个人而言,我会使用整数版本,但是STM32F4部件只有一个精度FPU,因此在这种情况下,缺少硬件浮点并不是一个问题--尽管还有其他避免浮点的原因。然后,Servo::setPosition()函数根据脉冲宽度接受位置参数,并且如上所述,这与给定所建议的初始化的位置标度0到20000有关。所以你要么需要:
float set_point = input.read() ;
output.SetPosition( (int)( (set_point * 1000) + 1000 ) ; // Scale to 1 to 2ms或
uint16_t set_point = input.read_u16() ;
output.SetPosition( ((set_point * 1000) >> 16) + 1000 ) ;把所有这些加在一起(加上一些其他的改进):
#include "mbed.h"
#include "Servo.h"
int main()
{
// Hardware parameters
static const int SERVO_FREQ = 50 ; // Hz
static const int SERVO_PERIOD = 1000000 / SERVO_FREQ ; // microseconds
static const int SERVO_MIN = 1000 ; // 1ms in microseconds
static const int SERVO_MAX = 2000 ; // 2ms in microseconds
static const int SERVO_RANGE = SERVO_MAX - SERVO_MIN ;
// I/O configuration
AnalogIn input( A1 ) ;
Servo output( D6 ) ;
output.Enable( SERVO_MIN, SERVO_PERIOD ) ;
// Control loop
for(;;)
{
float set_point = input.read() ; // 0.0 to 1.0
output.SetPosition( set_point * SERVO_RANGE + SERVO_MIN ) ; // 1 to 2ms
wait_us( SERVO_PERIOD ) ; // wait for one complete PWM cycle.
}
}定点版本将包括:
uint16_t set_point = input.read_u16() ; // 0 to 2^16
output.SetPosition( ((set_point * SERVO_RANGE) >> 16) // 1 to 2ms
+ SERVO_MIN ) ;在循环中。
请注意,这不是最优雅的Servo类实现。它只不过是一个PWM类。如果将最小/最大脉冲宽度与周期一起传递给构造函数,这样您就可以给它一个零到n个设置点,而不是绝对脉冲宽度,这样会更好。这样,就可以简化一些神秘的产值计算,因为Servo类将通过适当的范围检查为您完成这一任务。实际上,如果位置参数是uint16_t,范围为0到65535,那么所有可能的输入值都是有效的,您可以直接将AnalogIn::read_u16()的输出传递给它,这样您的循环就可以包含:
output.SetPosition_u16( input.read_u16() ) ;
wait_us( SERVO_PERIOD ) ;换句话说--获得一个更好的Servo类或者编写自己的类--在封装伺服控制专业知识方面,这对你没什么好处。
发布于 2020-05-21 04:23:08
即时观察
我现在看到了五个问题,从“可能的问题”到“可能的问题”。我能辨认出你照片上的别针标签,你的引脚分配似乎是正确的。假设没有奇怪的电线或电压问题:
AnalogIn,而不是AnalogOut。虽然AnalogOut具有read的能力,但它用于反馈,以确保您的输出符合您的预期。现在,作为一个AnalogOut,你实际上是作为一个电压源在这个引脚上设置电压,而不是测量电压。Servo::Enable打电话。文档告诉您如何调用Servo::Enable。一定要叫它。您甚至需要指定伺服的起始位置,这将允许您对输出和伺服进行故障排除(请参阅稍后的故障排除)。AnalogIn::read返回[0.0, 1.0]之间的float,以表示输入线路上读取的电压与系统电压(通常为5V或3.3V )之间的比率。然而,Servo::SetPosition需要一个整数来表示脉冲信号的正向部分的长度(以微秒为单位--在0到20,000之间)。如果您试图将AnalogIn::read的结果传递给Servo::SetPosition,那么您的float将被转换为0(除了只有一个罕见的情况是1)。您需要将模拟输入转换为整数输出。for循环。它除了乱七八糟的代码之外,什么也不做。如果您希望在将来的某个时候使用i的值,那么就把它留在这里,否则就放弃它。故障排除
幸运的是,许多系统可以被认为是许多盒子(子系统)之间画出箭头。如果所有的框都正确地完成了它们的工作,并且插入了正确的下一个框,那么整个系统作为一个整体就可以工作了。您的系统如下所示:
+-----+ +-----+ +----------------+ +-------------+ +--------------------+ +-----+ +-------+
| Pot |-->| ADC |-->| AnalogIn::read |-->| Float-to-us |-->| Servo::SetPosition |-->| PWM |-->| Servo |
+-----+ +-----+ +----------------+ +-------------+ +--------------------+ +-----+ +-------+所有这些子系统构成了整个系统。如果其中一个链接不能正常工作,那么整个链接就不能正常工作了。通常(或者至少当我们有时间时我们会这样想),我们将测试应用于系统和子系统,以确保它们根据输入产生预期的输出。如果您将输入应用到其中一个框中,并且输出是您所期望的,则该框是好的。给它一个绿色的检查标记,然后移到下一个。
对每一种情况的测试可能如下所示:
AnalogIn::read**:**输入: ADC的寄存器值。输出:有些浮动在0.0到1.0之间。我们可以同时测试模数转换器和AnalogIn::read功能,将它们作为一个子系统,以引脚电压为输入,以浮点值作为输出。同样,对于这一点,您需要一些调试功能。要么打印语句,要么是串行连接,要么是开发环境之类的。Servo::SetPosition输入:一个0到20,000之间的整数,表示输出脉宽调制(PWM)信号的占空比(高周期)。产出:增加这一数字会增加观察到的占空比。减少会减少。在我们中,占空比的长度大约等于代码中的设定长度。你需要一个示波器来观察任务周期。或者,如果您的伺服工作,那么您应该看到它移动时,这一变化。结论
将您的系统视为一系列子系统。独立测试每一个。您不能期望下一个子系统“弥补”前面子系统的不足。他们都需要工作。
https://stackoverflow.com/questions/61926697
复制相似问题