Hi, Members kindly helped me out a few weeks back with my thermometer sketch, which works fine, however, I want to slow the servo movement as it's very jerky. Can anybody offer some advice as to how I can incorporate a delay? into my existing code, please. I entered a delay after the digital write command, not making any difference. (the delay command is not important to the control program) The servo is an MG90S and works directly from pin 5 and actuates a drum with an angle of 0 >180` The servo tends to be very jerky.
Here is my sketch:-
/* Atmega 328
*
* tested 10/02/2024
*/
#include <Servo.h>
#include <OneWire.h>
#include <DallasTemperature.h>
const int SERVO_PIN = 5; // Arduino pin connected to Servo Motor's pin
const int SENSOR_PIN = 2; // Arduino pin connected to DS18B20 sensor's DATA pin
const float TEMPERATURE_THRESHOLD = 30; // °C 20
Servo servo; // create servo object to control a servo
OneWire oneWire(SENSOR_PIN); // setup a oneWire instance
DallasTemperature sensor(&oneWire); // pass oneWire to DallasTemperature library
float temperature;
float servopos;
void setup() {
Serial.begin(9600); // initialize serial
servo.attach(SERVO_PIN); // attaches the servo on pin 5 to the servo object
sensor.begin(); // initialize the sensor
}
void loop() {
delay(1000);
sensor.requestTemperatures(); // send the command to get temperatures
temperature = sensor.getTempCByIndex(0); // read temperature in Celsius
servopos = (180.0 / 12.0) * (temperature-10.0); //servopos = 180 - servoposraw; // 20
if (servopos < 0) servopos = 0;
if (servopos > 180) servopos = 180;
servo.write(servopos);
delay (15);
Serial.println(servopos);
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.print("°C => servo angle: ");
}
@Jevray
You need to smooth out the temperature measurements
Take maybe 10 measurements with a 10 ms delay between each.
Add the measurements and divide by 10 to get an average
@jim-p, thanks for your reply, I'm not too concerned with the temperature measurements as this project is for home room temperature monitoring. It uses quite an elaborate mechanism and it's not a smooth transition, mainly when first powered up, any changes in room temperature are gradual and will only need to be checked every minute (to be decided) This is the first time I've used servo's, so still learning. I'm very much a novice when it comes to writing code, so must confess it's taken me many hours just to get this far. So if I can smooth out the jerks at power-up, or for any reason a sudden temperature, then that would be ideal.
@Jevray The purpose of temperature averaging is to get rid of signal noise. No sensor is perfect, and with your 15 degrees turn per degree of temperature change, reading noise will cause your servo to be twitchy.
@jim-p, (It uses quite an elaborate mechanism) The servo turns a drum through 180, using nylon cords and pulleys. A vertical-mounted pointer moves positionally, upwards as the temperature rises, and vice-versa as the temperature drops. The scale length is 188mm, with active readings between 10 min and 30 max, without heating, falling to around 16, 20` would be a steady average in a warm room. Readings don’t need to be taken every second, as the rate of change over a short time does not alter that much. The thermistor will be mounted on a thermal plate so that any rapid changes in air temperature won’t be reflected in the readings. The movements between the degrees markers, I want to make slower if possible, but the fastest movement occurs at power-up when the servo hits zero before hitting the target temperature. Thinking! Could I enter a servo angle within start-up which would represent say 16 degrees, the servo position would have less travel distance?
@ noiasca
Hi, I came across that link using millis while searching for tips, but incorporating that idea into my existing code will not be easy for me as a novice to contemplate, It's not just a question of altering a few lines of code to make it work, my attempts often run into hours of frustration, not knowing enough about the way to go. But I will take a look, and I thank you for your advice. Jevray
@Jevray in a loop, print 100 temperature readings, and look at how stable they are/aren't. Analyse the output, and look for the typical step change from one reading to the next. If the step change is 0.2 degree, then you're looking at a 3 degree change in your servo command. Is that acceptable? If not, you have to smooth the data. Doesn't matter what else you do, that noise needs quelling.
@camsysca, thanks for your input. I used a project board to test all was working ok, and the usb ports from my laptop and Nano supplied the power and programming. Since mounting everything on the perf board including a barrel jack, for an 8v external power input to Vin, I have uncovered a problem! the Nano is locking up with all onboard LEDs lit? I can reset it and it will print the current temperature, only to repeat this effect. The 5v Nano output, may not be supplying enough current to power the servo under load. Before going anyfurther, I'm going to power the servo from an external 5v feed and run some more checks, I will report back. Jevray
Following on from my last post, the 5v servo supply has been transferred to an independent 5v regulated and smoothed supply circuit. I'm now left with an annoying fast ticking sound emanating from within the servo, the holding pulse is the culprit! The Arduino servo sweep example was also tested, just to prove the servo's performance was good. This noise is irritating, it wasn't present when I initially assembled it using my breadboard lash-up, but only appeared since transferring to the perf board. The parts layout and wiring are good, with no ground loops.
You may not need the full holding torque of the servo to hold the drum in place. The natural friction of the gears and motor may be sufficient.
So when you reach the desired set point, detach the servo, that will stop the software from sending pulses. When you need to move it again then re-attach.
@Jevray So, is this finished? If so, could you post your final code, and indicate the topic is solved, giving attribution to whomever you deem gave you the greatest help?
The reason to do this is, someone in the future may have a similar need, and come across your thread, then wonder what the outcome was.
Thank you for helping keep this forum operating at it's best.
@jim-p, yes that's a good tip, thanks for posting, I'll give it a try. Once I've sorted out all the issues and I'm happy with the code I'll post the final sketch.
Regards Jevray
This will be my final post regarding servo issues. To sum up, I scraped the perf-board in favour of pre-tinned strip board, isolated the 5volt servo supply, by using a separate 5v regulator and 470mfd smoothing cap. The grounding was also improved to avoid possible loops. The main problem however was associated with the MG90S servo! The Arduino sweep test sketch was loaded and worked fine until dead spots showed up when the servo was put under a light-fingered load! followed by the mechanical load ticking, annoying as this was a new boxed item. So I’ve replaced it with an MG996R, so all my problems appear to have been solved.
I’d like to thank all those who have offered help and suggestions and in particular.. @camsysca, and @Jim-p. Finally, I’ve included my code, which works fine for my application. Regards Dupe.
/* Atmega 328
tested 16/02/2024
*/
#include <Servo.h>
#include <OneWire.h>
#include <DallasTemperature.h>
const int SERVO_PIN = 5; // Arduino pin connected to Servo Motor's pin
const int SENSOR_PIN = 2; // Arduino pin connected to DS18B20 sensor's DATA pin
const float TEMPERATURE_THRESHOLD = 30; // °C 20?
Servo servo; // create servo object to control a servo
OneWire oneWire(SENSOR_PIN); // setup a oneWire instance
DallasTemperature sensor(&oneWire); // pass oneWire to DallasTemperature library
float temperature;
float servopos;
void setup() {
servo.write (0);
Serial.begin(9600); // initialize serial
servo.attach(SERVO_PIN); // attaches the servo on pin 5 to the servo object
sensor.begin(); // initialize the sensor
}
void loop() {
delay(10000);
sensor.requestTemperatures(); // send the command to get temperatures
temperature = sensor.getTempCByIndex(0); // read temperature in Celsius
servopos = (180.0 / 10.0) * (temperature - 10.0); //servopos = 180 - servoposraw; // 20
if (servopos < 0) servopos = 0;
if (servopos > 180) servopos = 180;
servo.write(servopos);
Serial.println(servopos);
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.print("°C => servo angle: ");
}