First of all it's great to see that you're back at developing this library!
Would it be possible to add servo slower functionality to ServoOut?
You're doing a great job and you're a huge help to the community.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I've added ticket [#50] for this for the next release. It shouldn't be that difficult to implement, something similar is already available in the Retracts and DAIPin classes.
I probably won't add this to ServoOut directly since that would clutter the class. I think it should be part of the Channel class so it'll sit right next to channel reverse and endpoints, which seems to be where high end transmitters also put this feature.
If you need something that can operate directly on milliseconds (in case you want to tie PPMIn to ServoOut directly) then I can arrange that as well.
Here's a test implementation of the ServoSpeed class and a modified servo out example. You can specify servo speed in deciseconds (0.1 sec) to indicate how much time it should take the servo to travel from one extreme to the other, range is 0 (instant) to 100 (10 seconds). It operates in the microseconds domain, so you can supply a value in us (from PPMIn for example) and feed the output to ServoOut if you want to.
The same will be added to the Channel class in release 0.4, but that will operate on normalized values instead of microseconds.
You'll need one ServoSpeed object for each servo, since each object keeps track of time and progress individually. See the attached zip file for sources and example.
I haven't thoroughly tested it yet, so if you find any bugs, let me know :)
ServoSpeed.h:
#ifndefINC_RC_SERVOSPEED_H#defineINC_RC_SERVOSPEED_H/* ---------------------------------------------------------------------------** This software is in the public domain, furnished "as is", without technical** support, and with no warranty, express or implied, as to its usefulness for** any purpose.**** ServoSpeed.h** Custom class to implement servo speed in the microsecond domain** For direct use in combination with PPMOut and ServoOut**** Author: Daniel van den Ouden** Project: ArduinoRCLib** Website: http://sourceforge.net/p/arduinorclib/** -------------------------------------------------------------------------*/#include<inttypes.h>namespacerc{/*! * \brief Class to encapsulate Servo Speed functionality.* \details This class implements servo speed in the microsecond domain.* \author Daniel van den Ouden* \date Nov-2012* \copyright Public Domain.*/classServoSpeed{public:/*! \brief Constructs a ServoSpeed object \param p_speed Speed in deciseconds, 0 = instant, range [0 - 100].*/ServoSpeed(uint8_tp_speed=0);/*! \brief Sets the servo speed; the time it takes to travel between servo extremes. \param p_speed The time it takes to travel between both extremes in deciseconds (0.1 sec), range [0 - 100] (instant - 10 sec). \note Default is 0 (instant). \note To convert degrees per second to speed, use deg per sec = total throw in degrees / (speed / 10). The other way around: speed = (throw in deg / deg per sec) * 10.*/voidsetSpeed(uint8_tp_speed);/*! \brief Gets the servo speed. \return The time it takes to travel between two extremes in deciseconds, range [0 - 100].*/uint8_tgetSpeed()const;/*! \brief Applies servo speed. \param p_target Input value in microseconds, range center +- travel (see util.h). \return Output value with speed applied in microseconds, range center +- travel (see util.h)*/uint16_tapply(uint16_tp_target);private:uint8_tm_speed;//!< Servo speeduint8_tm_time;//!< Last time update was calleduint16_tm_last;//!< Value of last update};}// namespace end#endif// INC_RC_SERVOSPEED_H
ServoSpeed.cpp
/* ---------------------------------------------------------------------------** This software is in the public domain, furnished "as is", without technical** support, and with no warranty, express or implied, as to its usefulness for** any purpose.**** ServoSpeed.cpp** Channel functionality**** Author: Daniel van den Ouden** Project: ArduinoRCLib** Website: http://sourceforge.net/p/arduinorclib/** -------------------------------------------------------------------------*/#include<Arduino.h>#include<ServoSpeed.h>#include<util.h>namespacerc{// Public functionsServoSpeed::ServoSpeed(uint8_tp_speed):m_speed(0),m_time(0),m_last(0){setSpeed(p_speed);}voidServoSpeed::setSpeed(uint8_tp_speed){m_speed=p_speed;m_time=static_cast<uint8_t>(millis());}uint8_tServoSpeed::getSpeed()const{returnm_speed;}uint16_tServoSpeed::apply(uint16_tp_target){// handle first callif(m_last==0){m_last=p_target;}if(m_speed==0||p_target==m_last){returnp_target;}// we might as well use 8 bit for times, just make sure to update at least 4 times per second// (1000 ms / 256 = 3.9 overflows per second)uint8_tnow=static_cast<uint8_t>(millis());uint8_tdelta=now-m_time;m_time=now;// the total amount traveled in the past delta time is:// (full throw / time which it takes to travel in millis) * delta time in millis// or// (2 * rc::getTravel() / (m_speed * 100)) * delta// that'll result in 0 for any speed above 10 or so, so let's not do that// but the following is the same:// (delta * 2 * rc::getTravel()) / (m_speed * 100)// but this will overflow for delta >= about 64, so we're going to use 32 bit longs hereuint16_ttravel=static_cast<uint16_t>((delta*static_cast<uint32_t>(rc::getTravel())*2)/(m_speed*100));// now that we know how far we can travel in this update, let's see in which direction we'll need to goif(m_last>p_target){if(static_cast<uint32_t>(m_last-p_target)<travel){m_last=p_target;}else{m_last=m_last-static_cast<int16_t>(travel);}}else{if(static_cast<uint32_t>(p_target-m_last)<travel){m_last=p_target;}else{m_last=m_last+static_cast<int16_t>(travel);}}returnm_last;}// namespace end}
Modified servoout_example.pde
/* ---------------------------------------------------------------------------** This software is in the public domain, furnished "as is", without technical** support, and with no warranty, express or implied, as to its usefulness for** any purpose.**** servoout_example.pde** Demonstrate Servo Signal Output functionality**** Author: Daniel van den Ouden** Project: ArduinoRCLib** Website: http://sourceforge.net/p/arduinorclib/** -------------------------------------------------------------------------*/#include<ServoOut.h>#include<ServoSpeed.h>#include<Timer1.h>#define SERVOS 4uint8_tg_pinsIn[SERVOS]={A0,A1,A2,A3};// Input pinsuint8_tg_pinsOut[SERVOS]={2,3,4,5};// Output pinsuint16_tg_input[SERVOS];// Input buffer for servoOut, microsecondsuint8_tg_work[SERVOOUT_WORK_SIZE(SERVOS)];// we need to have a work buffer for the ServoOut class// ServoOut requires three buffers:// Pins buffer containing output pins// Input buffer containing input values in microseconds// Work buffer of SERVOOUT_WORK_SIZE(SERVOS) elements for internal calculations// This setup removes any technical limit on the number of servos you want,// and makes sure the library doesn't use more memory than it really needs,// since the client code supplies the buffers.rc::ServoOutg_ServoOut(g_pinsOut,g_input,g_work,SERVOS);// define a servo speed object for each servorc::ServoSpeedg_ServoSpeed[SERVOS];voidsetup(){// Initialize timer1, this is required for all features that use Timer1// (PPMIn/PPMOut/ServoIn/ServoOut)rc::Timer1::init();for(uint8_ti=0;i<SERVOS;++i){// set up input pinspinMode(g_pinsIn[i],INPUT);// set up output pinspinMode(g_pinsOut[i],OUTPUT);// put them lowdigitalWrite(g_pinsOut[i],LOW);// fill input buffer, convert raw values to normalized onesg_input[i]=map(analogRead(g_pinsIn[i]),0,1024,1000,2000);g_ServoSpeed[i].setSpeed(i*10);// instant for servo 0, 1 second for 1, 2 seconds for 2 etc}g_ServoOut.start();}voidloop(){// update the input bufferfor(uint8_ti=0;i<SERVOS;++i){// fill input buffer, convert raw values to normalized onesg_input[i]=map(analogRead(g_pinsIn[i]),0,1024,1000,2000);g_input[i]=g_ServoSpeed[i].apply(g_input[i]);// apply servo speed}// tell ServoOut there are new values available in the input bufferg_ServoOut.update();// Just a quick note here to keep in mind// If you're having problems getting your servos to work properly, i.e. servos are not responding well// or seem to miss their input signal every couple of seconds, then the servos may be disturbing their control signal.// This happens especially when you've connected the servos directly to the Arduino and when they are of poor quality.// The motor of the servo will cause drops in the voltage of the Arduino which will mess with the generated signal,// I've had this happen to me while using some cheap Esky micro servos. If you hook the signal up to a scope you// can see voltage drops in the signal every few hundred microseconds while the servo's motor is working.// To fix this you need a couple of decoupling capacitors, google for more details ;)}
Last edit: dvdouden 2012-11-20
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I've just tested the code (both the test code posted here and the final code in Channel) and it works fine, really cool feature. Thanks for the suggestion!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
No need to thank me, but Thank you! I'll be testing this during the weekend, but this sounds absolutely amazing.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2013-01-14
I finally had the time to test this and it works great! Tested the whole "loop". PPM data read with PPMIn and outputted to servo with ServoOut via ServoSpeed.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
First of all it's great to see that you're back at developing this library!
Would it be possible to add servo slower functionality to ServoOut?
You're doing a great job and you're a huge help to the community.
Thanks for your interest in the library!
I've added ticket [#50] for this for the next release. It shouldn't be that difficult to implement, something similar is already available in the Retracts and DAIPin classes.
I probably won't add this to ServoOut directly since that would clutter the class. I think it should be part of the Channel class so it'll sit right next to channel reverse and endpoints, which seems to be where high end transmitters also put this feature.
If you need something that can operate directly on milliseconds (in case you want to tie PPMIn to ServoOut directly) then I can arrange that as well.
Related
Tickets:
#50Hi!
You guessed right, between PPMIn and ServoOut would be perfect!
Here's a test implementation of the ServoSpeed class and a modified servo out example. You can specify servo speed in deciseconds (0.1 sec) to indicate how much time it should take the servo to travel from one extreme to the other, range is 0 (instant) to 100 (10 seconds). It operates in the microseconds domain, so you can supply a value in us (from PPMIn for example) and feed the output to ServoOut if you want to.
The same will be added to the Channel class in release 0.4, but that will operate on normalized values instead of microseconds.
You'll need one ServoSpeed object for each servo, since each object keeps track of time and progress individually. See the attached zip file for sources and example.
I haven't thoroughly tested it yet, so if you find any bugs, let me know :)
ServoSpeed.h:
ServoSpeed.cpp
Modified servoout_example.pde
Last edit: dvdouden 2012-11-20
Sourceforge is acting up, here's the attachment
Last edit: dvdouden 2012-11-20
I've just tested the code (both the test code posted here and the final code in Channel) and it works fine, really cool feature. Thanks for the suggestion!
No need to thank me, but Thank you! I'll be testing this during the weekend, but this sounds absolutely amazing.
I finally had the time to test this and it works great! Tested the whole "loop". PPM data read with PPMIn and outputted to servo with ServoOut via ServoSpeed.