PJRC Encoder Object as Property of Another Object - c++

I'm borrowing PJRC's Encoder library to manage a stepper-powered syringe pump I am running off a Sparkfun RedBoard and a BigEasy Driver.
I've been developing the program modularly, defining lower-level classes first and working up from there. It is my desire that higher-level classes take instances of lower classes as properties. In my current nightmare, I'm building a syringe Pump class with Stepper motor and Encoder objects as properties.
I'm organizing the library into a header file and '.cpp' file as recommended by the Arduino Tutorials. The Pump class is declared as follows in 'Pump.h':
#include "Arduino.h"
#include "Stepper.h"
#include "Encoder.h"
#define PUMP_TOP_SPEED 50 // ml/min top pump speed
#define PUMP_ERROR 10 // encoder counts acceptable error
class Pump {
private:
Stepper motor; // object stepper motor
Encoder encoder; // object attached encoder
int countPerRev; // # encoder counts per relovlution
float nominalVolume; // mL nominal syringe volume
float innerDiameter; // cm syringe inner diameter
float shaftLead; // cm driveshaft threading lead distance
float degVolume; // mL effective volume change per degree of rotation
bool state; // boolean T = ready, F = slept
public:
// constructor
Pump(const Stepper& stp, const Encoder& enc, int cpr, float vol, float diam, float lead);
float volume(); // returns nominalVolume
float position(); // returns current pump position in mL
void hold(); // high power state to resist back-pressure
void relax(); // low power state
void pump(float vol, float rate); // pumps the requested volume at requested rate
void release(); // moves the plunger all the way out so syringe can be serviced
void set(); // returns plunger to zero mL
};
The relevant code in 'Pump.cpp' file which I have been testing with is the constructor and the definition of the pump() method, which goes like so:
// constructor
Pump::Pump(const Stepper& stp, const Encoder& enc, int cpr, float vol, float diam, float lead) : motor(stp), encoder(enc), countPerRev(cpr), nominalVolume(vol), innerDiameter(diam), shaftLead(lead) {
// calculate volume per degree
// (diameter^2 / 4) * PI * (lead / 360) = mL / deg
// diam * diam * lead * PI / 360 / 4 = (diam diam lead PI) / 1440
degVolume = innerDiameter * innerDiameter * shaftLead * PI / 1440;
// construct the encoder inside here
/*encoder = new(Encoder(2,3));
// set it to 0
encoder.write(0);*/
}
// pumping function
void Pump::pump(float vol, float rate) {
/*
vol < 0 INFUSE
vol > 0 WITHDRAW
*/
if (rate > PUMP_TOP_SPEED) rate = PUMP_TOP_SPEED; // limit rate
if (!state) hold(); // wake up the motor if it's asleep
// make sure this doesn't push outside of the acceptable range
if (position() + vol <= nominalVolume && position() + vol >= 0) {
// (mL) / (mL/deg) = deg
float degrees = vol / degVolume; // find number of degrees to turn the motor
Serial.print("Looking to turn ");
Serial.print(degrees, DEC);
Serial.print(" degrees at ");
// (count) + (deg) * (count/rev) / (deg/rev) = count
long goal = encoder.read() + degrees * countPerRev / 360; // set target encoder reading
// (mL/min) / (mL/deg) / (deg/rev) = RPM
int rpm = abs(rate) / degVolume / 360; // find RPM to turn the motor
Serial.print(rpm, DEC);
Serial.println(" RPM in full-stepping mode");
Serial.print("Going from encoder count ");
Serial.print(encoder.read(), DEC);
Serial.print(" to ");
Serial.println(goal, DEC);
motor.drive(degrees, 1, rpm); // drive the pump
int err = goal - encoder.read(); // how far from the goal are we in counts?
Serial.print("Reached encoder count ");
Serial.println(encoder.read(), DEC);
Serial.print("Missed by ");
Serial.println(err, DEC);
}
}
I've been testing my pump() method and threw in a whole bunch of Serial.print() to try to debug and figure out what is happening and from what I can see, the Encoder object that is a property of the Pump object doesn't have its position updated as the shaft turns, whereas the Encoder object declared in the Arduino sketch and passed to the Pump constructor does.
As you can see above I've tried to initialize the encoder within the pump constructor but the 2 or 3 things I tried all threw a bunch of cryptic errors in the Arduino IDE when I tried to compile, left that commented out section so you can see what I was trying.
What I find exceedingly annoying is that while my own Stepper object works fine, the Pump object can turn the motor, the Encoder object won't function inside the Pump object. When I run the sketch:
#include <Stepper.h>
#include <Encoder.h>
#include <Pump.h>
// initialize stepper
Stepper motor(4, 5, 6, 7, 8, 9, 10, 11);
// initialize encoder
Encoder encoder(2, 3);
// initialize the pump
Pump pump(motor, encoder, 1440, 25, 2.328, 0.1);
void setup() {
// start the Serial connection
Serial.begin(9600);
// set up the motor
motor.enable();
motor.reset();
// pump
pump.pump(0.25,25);
Serial.print("Pump reading: ");
Serial.println(pump.position(), DEC);
Serial.print("Encoder reading: ");
Serial.println(encoder.read(), DEC);
// cool boards
pump.relax();
}
void loop() {}
I get back the following in the Serial monitor:
Looking to turn 211.4397277832 degrees at 58 RPM in full-stepping mode
Going from encoder count 0 to 845
Reached encoder count 0
Missed by 845
Pump reading: 0.0000000000
Encoder reading: 845
So, the method encoder.read() always returns zero in the Pump object but when I called it at the end of my sketch in the setup() function it turns I turned exactly as far as I wanted to.
Thank you for reading. I'd appreciate guidance on how to either properly pass an active Encoder object to Pump, or how to properly initialize an Encoder object within Pump without freaking out the compiler.

The key was, in-fact, to initialize the encoder within the Pump object, as I've been reading on the Arduino boards posted by people some variant of my issue.
I constructed the encoder within the property declarations of 'Pump.h'. Since the RedBoard I'm working with is an Arduino Uno, in essence, the only acceptable pins are 2 and 3 for interrupts. I declared the encoder with the following line under the class's list of private properties:
Encoder encoder = Encoder(2,3); // attached encoder
And it now works flawlessly. There is likely an option to pass the encoder pins to the Pump constructor and have it be flexible, but for the time being I need something that works more than I need something perfect.

Related

Delaying Movement of Servo after button press - Arduino

Recently I have been working on a project where the main goal is to move a servo on a model rocket to deploy a parachute. I want to make is so that 10 seconds after I press the button the parachute is released. I have some code for this already but It is not working, as it stops the code completely. Does anyone know how to fix this?
#include <Servo.h>
// constants won't change
const int BUTTON_PIN = 7; // Arduino pin connected to button's pin
const int SERVO_PIN = 9; // Arduino pin connected to servo motor's pin
Servo servo; // create servo object to control a servo
// variables will change:
int angle = 0; // the current angle of servo motor
int lastButtonState; // the previous state of button
int currentButtonState; // the current state of button
void setup() {
Serial.begin(9600); // initialize serial
pinMode(BUTTON_PIN, INPUT_PULLUP); // set arduino pin to input pull-up mode
servo.attach(SERVO_PIN); // attaches the servo on pin 9 to the servo object
servo.write(angle);
currentButtonState = digitalRead(BUTTON_PIN);
}
void loop() {
lastButtonState = currentButtonState; // save the last state
currentButtonState = digitalRead(BUTTON_PIN); // read new state
if(lastButtonState == HIGH && currentButtonState == LOW) {
Serial.println("The button is pressed");
time.delay(10000)
// change angle of servo motor
if(angle == 0)
angle = 90;
else
if(angle == 90)
angle = 0;
// control servo motor arccoding to the angle
servo.write(angle);
}
}
In Arduino, a delay is usually done with delay(10000); (for 10 seconds). I've never seen or heard of the time.delay() function, so that might be the issue. Otherwise the code looks like it should work as you want.
It also might depend on the board you're running it on. I remember having issues using delay() for long periods on an ESP8266 although I'm pretty sure that it is fine for tens of seconds.

MPU6050 how zeromotion works

Good evening to all. I am currently working on a project with smart windows in which I will measure temperature, humidity acceleration and I will have a gyroscope for the window degrees. I have decided which sensors I will continue with and one of them is the MPU6050. The question I want to ask is how can I use the sensor so that I can take measurements at the end of the acceleration and not at the beginning? The esp32 I have will be asleep all the time and will wake up every 15 minutes to send data out and if it receives an interrupt it will then wake up to send data. I have tried all the cases with motion but I have not succeeded
this is my code for zeromotion
#include "Wire.h"
#include "SPI.h"
// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050.h"
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 accelgyro;
int16_t ax, ay, az;
int16_t gx, gy, gz;
int8_t threshold, count;
float temp;
bool zero_detect;
bool TurnOnZI = false;
bool XnegMD, XposMD, YnegMD, YposMD, ZnegMD, ZposMD;
int minVal=265; int maxVal=402;
double x; double y; double z;
#define LED_PIN 13
#define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex
RTC_DATA_ATTR int bootCount = 0;
bool blinkState = false;
void print_wakeup_reason() {
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch (wakeup_reason)
{
case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
default : Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
}
}
void setup() {
// join I2C bus (I2Cdev library doesn't do this automatically)
Wire.begin();
// initialize serial communication
// (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
// it's really up to you depending on your project)
Serial.begin(115200);
//Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));
//Print the wakeup reason for ESP32
print_wakeup_reason();
// initialize device
Serial.println("Initializing I2C devices...");
accelgyro.initialize();
// verify connection
Serial.println("Testing device connections...");
Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
esp_sleep_enable_ext0_wakeup(GPIO_NUM_15, 1); //1 = High, 0 = Low
//accelgyro.setTempSensorEnabled(false);
//Set up zero motion
/** Get accelerometer power-on delay.
The accelerometer data path provides samples to the sensor registers, Motion
detection, Zero Motion detection, and Free Fall detection modules. The
signal path contains filters which must be flushed on wake-up with new
samples before the detection modules begin operations. The default wake-up
delay, of 4ms can be lengthened by up to 3ms. This additional delay is
specified in ACCEL_ON_DELAY in units of 1 LSB = 1 ms. The user may select
any value above zero unless instructed otherwise by InvenSense. Please refer
to Section 8 of the MPU-6000/MPU-6050 Product Specification document for
further information regarding the detection modules.
#return Current accelerometer power-on delay
#see MPU60X0_RA_MOT_DETECT_CTRL
#see MPU60X0_DETECT_ACCEL_ON_DELAY_BIT
*/
accelgyro.setAccelerometerPowerOnDelay(3);
/** Get Zero Motion Detection interrupt enabled status.
Will be set 0 for disabled, 1 for enabled.
#return Current interrupt enabled status
#see MPU60X0_RA_INT_ENABLE
#see MPU60X0_INTERRUPT_ZMOT_BIT
**/
accelgyro.setIntZeroMotionEnabled(true);
//accelgyro.setIntMotionEnabled(true);
/** Get the high-pass filter configuration.
The DHPF is a filter module in the path leading to motion detectors (Free
Fall, Motion threshold, and Zero Motion). The high pass filter output is not
available to the data registers (see Figure in Section 8 of the MPU-6000/
MPU-6050 Product Specification document).
The high pass filter has three modes:
Reset: The filter output settles to zero within one sample. This
effectively disables the high pass filter. This mode may be toggled
to quickly settle the filter.
On: The high pass filter will pass signals above the cut off frequency.
Hold: When triggered, the filter holds the present sample. The filter
output will be the difference between the input sample and the held
sample.
ACCEL_HPF | Filter Mode | Cut-off Frequency
----------+-------------+------------------
0 | Reset | None
1 | On | 5Hz
2 | On | 2.5Hz
3 | On | 1.25Hz
4 | On | 0.63Hz
7 | Hold | None
</pre>
#return Current high-pass filter configuration
#see MPU60X0_DHPF_RESET
#see MPU60X0_RA_ACCEL_CONFIG
*/
//DEBUG_PRINTLN("Setting DHPF bandwidth to 5Hz...");
accelgyro.setDHPFMode(1);
/** Get motion detection event acceleration threshold.
This register configures the detection threshold for Motion interrupt
generation. The unit of MOT_THR is 1LSB = 2mg. Motion is detected when the
absolute value of any of the accelerometer measurements exceeds this Motion
detection threshold. This condition increments the Motion detection duration
counter (Register 32). The Motion detection interrupt is triggered when the
Motion Detection counter reaches the time count specified in MOT_DUR
(Register 32).
The Motion interrupt will indicate the axis and polarity of detected motion
in MOT_DETECT_STATUS (Register 97).
For more details on the Motion detection interrupt, see Section 8.3 of the
MPU-6000/MPU-6050 Product Specification document as well as Registers 56 and
58 of this document.
#return Current motion detection acceleration threshold value (LSB = 2mg)
#see MPU60X0_RA_MOT_THR
*/
//Serial.println("Setting motion detection threshold to 16...");
//accelgyro.setMotionDetectionThreshold(16);
/** Get zero motion detection event acceleration threshold.
This register configures the detection threshold for Zero Motion interrupt
generation. The unit of ZRMOT_THR is 1LSB = 2mg. Zero Motion is detected when
the absolute value of the accelerometer measurements for the 3 axes are each
less than the detection threshold. This condition increments the Zero Motion
duration counter (Register 34). The Zero Motion interrupt is triggered when
the Zero Motion duration counter reaches the time count specified in
ZRMOT_DUR (Register 34).
Unlike Free Fall or Motion detection, Zero Motion detection triggers an
interrupt both when Zero Motion is first detected and when Zero Motion is no
longer detected.
When a zero motion event is detected, a Zero Motion Status will be indicated
in the MOT_DETECT_STATUS register (Register 97). When a motion-to-zero-motion
condition is detected, the status bit is set to 1. When a zero-motion-to-
motion condition is detected, the status bit is set to 0.
For more details on the Zero Motion detection interrupt, see Section 8.4 of
the MPU-6000/MPU-6050 Product Specification document as well as Registers 56
and 58 of this document.
#return Current zero motion detection acceleration threshold value (LSB = 2mg)
#see MPU60X0_RA_ZRMOT_THR
*/
Serial.println("Setting zero-motion detection threshold to 156...");
accelgyro.setZeroMotionDetectionThreshold(64);
/** Get motion detection event duration threshold.
This register configures the duration counter threshold for Motion interrupt
generation. The duration counter ticks at 1 kHz, therefore MOT_DUR has a unit
of 1LSB = 1ms. The Motion detection duration counter increments when the
absolute value of any of the accelerometer measurements exceeds the Motion
detection threshold (Register 31). The Motion detection interrupt is
triggered when the Motion detection counter reaches the time count specified
in this register.
For more details on the Motion detection interrupt, see Section 8.3 of the
MPU-6000/MPU-6050 Product Specification document.
#return Current motion detection duration threshold value (LSB = 1ms)
#see MPU60X0_RA_MOT_DUR
*/
Serial.println("Setting motion detection duration to 40...");
//accelgyro.setMotionDetectionDuration(2);
/** Get zero motion detection event duration threshold.
This register configures the duration counter threshold for Zero Motion
interrupt generation. The duration counter ticks at 16 Hz, therefore
ZRMOT_DUR has a unit of 1 LSB = 64 ms. The Zero Motion duration counter
increments while the absolute value of the accelerometer measurements are
each less than the detection threshold (Register 33). The Zero Motion
interrupt is triggered when the Zero Motion duration counter reaches the time
count specified in this register.
For more details on the Zero Motion detection interrupt, see Section 8.4 of
the MPU-6000/MPU-6050 Product Specification document, as well as Registers 56
and 58 of this document.
#return Current zero motion detection duration threshold value (LSB = 64ms)
#see MPU60X0_RA_ZRMOT_DUR
*/
//Serial.println("Setting zero-motion detection duration to 0...");
accelgyro.setZeroMotionDetectionDuration(64);
//for (int i = 0; i < 1; i++) {
// read raw accel/gyro measurements from device
Serial.println("Getting raw accwl/gyro measurements");
//accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
Serial.println("Getting Motion indicators, count and threshold");
XnegMD = accelgyro.getXNegMotionDetected();
XposMD = accelgyro.getXPosMotionDetected();
YnegMD = accelgyro.getYNegMotionDetected();
YposMD = accelgyro.getYPosMotionDetected();
ZnegMD = accelgyro.getZNegMotionDetected();
ZposMD = accelgyro.getZPosMotionDetected();
zero_detect = accelgyro.getIntMotionStatus();
threshold = accelgyro.getZeroMotionDetectionThreshold();
//Serial.println("Got to count");
//count = accelgyro.getMotionDetectionCounterDecrement();
/** Get current internal temperature.
#return Temperature reading in 16-bit 2's complement format
#see MPU60X0_RA_TEMP_OUT_H
*/
Serial.println("Getting Die Temperature");
temp = (accelgyro.getTemperature() / 340.) + 36.53;
/* The accelerometer and gyroscope measurements are explained in the MPU-6050
datasheet in the GYRO_CONFIG and ACCEL_CONFIG register descriptions (sections 4.4
and 4.5 on pages 14 and 15). The scale of each depends on the sensitivity settings
chosen, which can be one of +/- 2, 4, 8, or 16g for the accelerometer and one of
+/- 250, 500, 1000, or 2000 deg/sec for the gyroscope. The accelerometer produces data
in units of acceleration (distance over time2), and the gyroscope produces data in units
of rotational velocity (rotation distance over time).
The output scale for any setting is [-32768, +32767] for each of the six axes. The default
setting in the I2Cdevlib class is +/- 2g for the accel and +/- 250 deg/sec for the gyro. If
the device is perfectly level and not moving, then:
X/Y accel axes should read 0
Z accel axis should read 1g, which is +16384 at a sensitivity of 2g
X/Y/Z gyro axes should read 0
In reality, the accel axes won't read exactly 0 since it is difficult to be perfectly level
and there is some noise/error, and the gyros will also not read exactly 0 for the same reason
(noise/error).
*/
// these methods (and a few others) are also available
accelgyro.getAcceleration(&ax, &ay, &az);
accelgyro.getRotation(&gx, &gy, &gz);
// Serial.print(temp); Serial.print(",");
// Serial.print(ax / 16384.); Serial.print(",");
// Serial.print(ay / 16384.); Serial.print(",");
// Serial.print(az / 16384.); Serial.print(",");
// Serial.print(gx / 131.072); Serial.print(",");
// Serial.print(gy / 131.072); Serial.print(",");
// Serial.print(gz / 131.072); Serial.print(",");
Serial.print(zero_detect); Serial.print(",");
//Serial.print(XnegMD); Serial.print(",");
//Serial.println(XposMD);
int xAng = map(ax,minVal,maxVal,-90,90);
int yAng = map(ay,minVal,maxVal,-90,90);
int zAng = map(az,minVal,maxVal,-90,90);
x= RAD_TO_DEG * (atan2(-yAng, -zAng)+PI);
y= RAD_TO_DEG * (atan2(-xAng, -zAng)+PI);
z= RAD_TO_DEG * (atan2(-yAng, -xAng)+PI);
Serial.print("AngleX= "); Serial.println(x);
Serial.print("AngleY= "); Serial.println(y);
Serial.print("AngleZ= "); Serial.println(z);
// display tab-separated accel/gyro x/y/z values
/*
Serial.print("a/g:\t");
Serial.print(ax/16384.); Serial.print("\t");
Serial.print(ay/16384.); Serial.print("\t");
Serial.print(az/16384.); Serial.print("\t");
Serial.print(gx/131.072); Serial.print("\t");
Serial.print(gy/131.072); Serial.print("\t");
Serial.println(gz/131.072);
Serial.print("DieTemp:\t");Serial.println(temp);
Serial.print("ZeroMotion(97):\t");
Serial.print(zero_detect); Serial.print("\t");
Serial.print("Count: \t");Serial.print(count); Serial.print("\t");
Serial.print(XnegMD); Serial.print("\t");
Serial.print(XposMD); Serial.print("\t");
Serial.print(YnegMD); Serial.print("\t");
Serial.print(YposMD); Serial.print("\t");
Serial.print(ZnegMD); Serial.print("\t");
Serial.println(ZposMD);
*/
// delay(1000);
// blink LED to indicate activity
// blinkState = !blinkState;
// digitalWrite(LED_PIN, blinkState);
//}
// configure Arduino LED for
//pinMode(LED_PIN, OUTPUT);
Serial.println("Going to sleep now");
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop() {
}
You should change your general concept. Opening a window can happen in "portions". So you can expect to get several motion-start and motion-stop interrupts. What you should do is: At first interrupt leave the device awake for - say - 3 seconds. If further interrupts come in, then restart your timer (called "retriggering" in HW timers). When the 3 seconds are gone, read the sensor to get the new window angle, send this info out, and then go to deep sleep again.

Issue with servo motor and potentiometer: not moving when program is inserted into board

This code is meant to utilize a potentiometer to turn a servomotor. When I tried to insert it into the program the servo didn't move at all, and I don't know if it is a result of my board, my wiring, or my code. If anyone could help or provide some assistance to the matter, it would much be appreciated. The board I am using is a Nucleo STM L476RG board and the motor is a micro 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);
}
}
}
Also, the code I was using had this code in the published library servo listed as 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
It also had a .cpp file in the same place as it so if anyone needs it as a reference I'll post it as an edit. I will also put the wiring just in case
The servo is an SG90.
The wiring of the board:
The first thing to understand is how the servo motor works. From the data sheet it requires a 50Hz PWM with a pulse width from 1 to 2ms. The pulse width determines the position, so a width of 1ms will position the servo at one end of its travel, a pulse of 2ms will set the position at the other end, and 1.5ms will set the centre position.
Second you need to read the documentation (in the comments) for the Servo class you are using. It even has example code. First you need to instantiate a Servo object (which you have done), then you need to Enable it by setting its pulse interval and initial pulse width (or position):
Servo output( D6 ) ;
output.Enable( 1500, 20000 ) ; // Centre position, 50Hz
Then if you want to read an analogue input, clearly you need an AnalogIn object:
AnalogOut input(A1);
Then you need to understand that a closed-loop control system must continuously read its input to adjust the output. Here you only read the potentiometer once before the control loop, so in the loop it never changes value so the position will not change. Moreover you have an entirely unnecessary inner loop that appears for come from the example code for an entirely different Servo implementation here - that example was not a closed-loop control system - it simply continuously cycles the servo back-and forth over its full range - that is not what you are trying to achieve in this case and it is just cargo cult programming.
In closed-loop control you continuously:
_______
| |
V |
get-input | <repeat>
set-output |
|_______|
Finally you need to understand that the units of the input measurement in this case are not the same as the units of the output setting - they need scaling so that the full scale input range maps to the full scale output range. The mbed AnalogIn class has two read functions; AnalogIn::read() returns a float in the range 0.0 to 1.0 and AnalogIn::read_u16 returns an uint16_t value 0 to 65535. Personally I'd use the integer version, but the STM32F4 parts have a single precision FPU, so the lack of hardware floating point is not an issue in this case - although there are other reasons for avoiding floating point. Then the Servo::setPosition() function takes a position argument in terms of the pulse width, and as explained above this relates to a position scale 0 to 20000 given the suggested initialisation. So you need either:
float set_point = input.read() ;
output.SetPosition( (int)( (set_point * 1000) + 1000 ) ; // Scale to 1 to 2ms
or
uint16_t set_point = input.read_u16() ;
output.SetPosition( ((set_point * 1000) >> 16) + 1000 ) ;
Putting all that together (with a few other refinements):
#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.
}
}
The fixed point version would have:
uint16_t set_point = input.read_u16() ; // 0 to 2^16
output.SetPosition( ((set_point * SERVO_RANGE) >> 16) // 1 to 2ms
+ SERVO_MIN ) ;
in the loop.
Note that this is not the most elegant Servo class implementation. It is little more than a PWM class. It would be better if the min/max pulse width were passed to the constructor along with the period so that you could just give it a zero to n set-point rather than an absolute pulse width. That way the somewhat arcane output value calculation would be simplified because the Servo class would do that for you with suitable range checks. In fact if the position parameter were a uint16_t and the range 0 to 65535, then all possible input values would be valid and you could pass the output of AnalogIn::read_u16() to it directly so your loop could just contain:
output.SetPosition_u16( input.read_u16() ) ;
wait_us( SERVO_PERIOD ) ;
In other words - get a better Servo class or write your own - this is doing little for you in terms of encapsulating servo control expertise.
Immediate observations
I see five issues right now, ranging from "maybe a problem" to "likely a problem". I was able to make out the pin labels on your photograph, and your pin assignments appear to be correct. Assuming there's no weird wire or voltage issues:
Your analog pin should be an AnalogIn, not an AnalogOut. While AnalogOut has the ability to read, that's used for feedback to make sure that your output is what you expect it to be. Right now, as an AnalogOut, you're actually acting as a voltage source on this pin and setting the voltage instead of measuring the voltage.
You're not calling Servo::Enable. The documentation tells you how to call Servo::Enable. Make sure to call it. You are even required to specify a starting position for the servo, and this will allow you to troubleshoot your output and servo (see troubleshooting later).
AnalogIn::read returns a float between [0.0, 1.0] to represent the ratio between the voltage read on the input line and the system voltage (5V or 3.3V usually). However, Servo::SetPosition expects an integer that represents the length (as an int in microseconds - between 0 and 20,000 in your case) of the positive part of the pulse signal. If you try to pass the result of AnalogIn::read to Servo::SetPosition, then your float will be converted to a 0 (except for the one single rare case when it's 1). You need to translate your analog input into an integer output.
Right now in your code you're only reading the status of the analog input pin at the very start of your program. You enter an infinite loop and never read this analog input again. You can twist that knob to your heart's content but it will never affect the program. You need to read the analog input many times. Move this inside of your loop.
Just a style thing, but you don't need that inner for loop. It doesn't do anything except clutter your code. If you're expecting to use the value of i at some point in the future then leave this in, but otherwise ditch it.
Troubleshooting
Luckily, many systems can be thought of as many boxes (subsystems) with arrows drawn between them. If all the boxes are doing their job correctly and they're plugged into the correct next box, then the entire system as a whole works. Your system looks like this:
+-----+ +-----+ +----------------+ +-------------+ +--------------------+ +-----+ +-------+
| Pot |-->| ADC |-->| AnalogIn::read |-->| Float-to-us |-->| Servo::SetPosition |-->| PWM |-->| Servo |
+-----+ +-----+ +----------------+ +-------------+ +--------------------+ +-----+ +-------+
All together these subsystems form your entire system. If one of these links isn't working correctly, the whole thing won't work correctly. Usually (or at least we like to imagine we will when we have the time), we apply tests to systems and subsystems to make sure that they produce expected output depending on their input. If you apply input to one of those boxes, and the output is what you expect, then that box is good. Give it a green check mark and move to the next one.
Testing for each of these could be something like:
Potentiometer: input: twist the knob, output: the voltage at the middle pin as near system voltage (5V or 3.3V) when turned all the way one way, close to 0 when turned to the opposite end, and has approximately linear progression between the two ends. You'll need a multimeter to measure this.
ADC (analog-to-digital converter): input: some voltage on the input pin. You can vary this by twisting the potentiometer, once you verify that's working. output: this is a little harder because the output is a register in the microcontroller. I don't know what the debugging environment looks like for your hardware, so I can't tell you how to measure this output. You can assume this works and move onto the next one if you don't know how to use the debugger (but you really should learn how to use your hardware's debugger)
AnalogIn::read: input: a register value of the ADC. output: some float between 0.0 and 1.0. We can test the ADC and the AnalogIn::read function at the same time by treating them as one subsystem, with pin voltage as the input and a float value as the output. Again for this you'll need some debugging functionality. Either print statements or a serial connection or a development environment or something.
Float to us conversion: input: a float between 0.0 and 1.0. output: an integer between 0 and 20,000, proportional (or inversely proportional, depending on desired functionality) to the float input. Again, since we're looking at variables, you'll need to use your debugging environment.
Servo::SetPosition input: an integer between 0 and 20,000 representing the duty cycle (high period) of your output pulse width modulated (PWM) signal. output: increasing this number increases the observed duty cycle. Decreasing decreases it. The length of the duty cycle in us is about equal to the set length in code. You'll need an oscilloscope to observe the duty cycle. Alternatively, if your servo is working, then you should see it move when this changes.
Servo: input: a PWM signal. output: an angular position. A 0% duty cycle should be all the way to one extreme, and a 100% duty cycle should be rotated to the other extreme.
Conclusion
Treat your system as a series of subsystems. Test each one independently. You can't expect the next subsystem to "make up for" the inadequacies of the one before it. They all need to work.

how to control servo motor with arduino

I saw many many videos on pwn and servo motor coding but can't understand how exactly the servo motor code works in arduino.
my main confusion is what is the exact purpose of delay in the below code.
when we say servo.write(180); doesn't it mean go to 180 degrees?
what is the use of the delay here?
some milliseconds cause the servo to work properly or jitter or vibrate not move or incorrect rotations etc.
include
Servo myservo; // create servo object to control a servo
// twelve servo objects can be created on most boards
int pos = 0; // variable to store the servo position
void setup() {
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}
void loop() {
for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(10); // waits 15ms for the servo to reach the position
}
The code attempts to get the servo to move relatively slowly from 0 to 180 degrees. 10 ms times 181 steps equals 1.81 seconds.
Most if not all servos are significantly faster than that if you just move straight from 0 to 180 in one go.
One problem with this code is that you don't know what the servo's initial position is. For instance, if the initial position is 180, it will quickly jump to 0 and then slowly move back to 180.
Also note that most servos are controlled with a signal every 20 ms or so, so changing the signal more often than that could lead to problems (like jitter/vibrations/noise/...).

Arduino Uno + servo motor (SG-90) + ultrasonic sensor(HC-S04) detects an obstacle

I'm a newbie to Arduino. The goal is to write a program that can stop a hypothetical conveyor belt (read a servo motor) if too many objects are stacked on a belt, that is detected by HC-S04 sensor. If the the distance exceeds the minimum threshold value (1000), then the motor can freely spin. If not, it should stop. With the code below, I get a servo motor to spin regardless of whether an object is in front of it or not.
Tried taking out and changing the delay. It just was spinning faster or slower, but still ignored obstacle distance. Tried commenting sensorValue = map(sensorValue, 0, 255, 0, 4000); but it didn't affect the result.
#include <Servo.h>
#include <Wire.h>
Servo servo;
const int trigPin= 9;
const int echoPin= 10;
const int threshold = 1000;
void setup() {
pinMode(trigPin, OUTPUT);
pinMode(echoPin,INPUT);
Serial.begin(9600);
servo.attach(8);
}
void loop() {
int sensorValue = digitalRead(echoPin);
sensorValue = map(sensorValue, 0, 255, 0, 4000);
if (sensorValue >= threshold) {
digitalWrite(8,HIGH);
delay(10);
}
else {
digitalWrite(8,LOW);
delay(10);
}
}
Debug by outputting your sensorValue contents - this will allow you to check which branch is triggered.
(can't post as a comment because my rep is not high enough).
You can use the debugging values to check, configure and calibrate your sensor.