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
/*---------------------------------------------------------------------------**Thissoftwareisinthepublicdomain,furnished"as is",withouttechnical**support,andwithnowarranty,expressorimplied,astoitsusefulnessfor**anypurpose.****ServoSpeed.cpp**Channelfunctionality****Author:DanielvandenOuden**Project:ArduinoRCLib**Website:http://sourceforge.net/p/arduinorclib/**-------------------------------------------------------------------------*/#include <Arduino.h>#include <ServoSpeed.h>#include <util.h>namespacerc{//PublicfunctionsServoSpeed::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){//handlefirstcallif(m_last==0){m_last=p_target;}if(m_speed==0||p_target==m_last){returnp_target;}//wemightaswelluse8bitfortimes,justmakesuretoupdateatleast4timespersecond//(1000ms/256=3.9overflowspersecond)uint8_tnow=static_cast<uint8_t>(millis());uint8_tdelta=now-m_time;m_time=now;//thetotalamounttraveledinthepastdeltatimeis://(fullthrow/timewhichittakestotravelinmillis)*deltatimeinmillis//or//(2*rc::getTravel()/(m_speed*100))*delta//that'll result in 0 for any speed above 10 or so, so let'snotdothat//butthefollowingisthesame://(delta*2*rc::getTravel())/(m_speed*100)//butthiswilloverflowfordelta>=about64,sowe're going to use 32 bit longs hereuint16_ttravel=static_cast<uint16_t>((delta*static_cast<uint32_t>(rc::getTravel())*2)/(m_speed*100));//nowthatweknowhowfarwecantravelinthisupdate,let's see in which direction we'llneedtogoif(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;}//namespaceend}
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>#defineSERVOS4uint8_tg_pinsIn[SERVOS]={A0,A1,A2,A3};//Inputpinsuint8_tg_pinsOut[SERVOS]={2,3,4,5};//Outputpinsuint16_tg_input[SERVOS];//InputbufferforservoOut,microsecondsuint8_tg_work[SERVOOUT_WORK_SIZE(SERVOS)];//weneedtohaveaworkbufferfortheServoOutclass//ServoOutrequiresthreebuffers://Pinsbuffercontainingoutputpins//Inputbuffercontaininginputvaluesinmicroseconds//WorkbufferofSERVOOUT_WORK_SIZE(SERVOS)elementsforinternalcalculations//Thissetupremovesanytechnicallimitonthenumberofservosyouwant,//andmakessurethelibrarydoesn't use more memory than it really needs,// since the client code supplies the buffers.rc::ServoOut g_ServoOut(g_pinsOut, g_input, g_work, SERVOS);// define a servo speed object for each servorc::ServoSpeed g_ServoSpeed[SERVOS];void setup(){ // Initialize timer1, this is required for all features that use Timer1 // (PPMIn/PPMOut/ServoIn/ServoOut) rc::Timer1::init(); for (uint8_t i = 0; i < SERVOS; ++i) { // set up input pins pinMode(g_pinsIn[i], INPUT); // set up output pins pinMode(g_pinsOut[i], OUTPUT); // put them low digitalWrite(g_pinsOut[i], LOW); // fill input buffer, convert raw values to normalized ones g_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();}void loop(){ // update the input buffer for (uint8_t i = 0; i < SERVOS; ++i) { // fill input buffer, convert raw values to normalized ones g_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 buffer g_ServoOut.update(); // Just a quick note here to keep in mind // If you'rehavingproblemsgettingyourservostoworkproperly,i.e.servosarenotrespondingwell//orseemtomisstheirinputsignaleverycoupleofseconds,thentheservosmaybedisturbingtheircontrolsignal.//Thishappensespeciallywhenyou'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'vehadthishappentomewhileusingsomecheapEskymicroservos.Ifyouhookthesignaluptoascopeyou//canseevoltagedropsinthesignaleveryfewhundredmicrosecondswhiletheservo'smotorisworking.//Tofixthisyouneedacoupleofdecouplingcapacitors,googleformoredetails;)}
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.