Follow along with the video below to see how to install our site as a web app on your home screen.
Nota: This feature may not be available in some browsers.
Dat verklaard precies de jitter. Vaak is de timing goed, af en toe gaat die net mis waardoord de servo wil bewegen.Het klopt inderdaad dat die PulsIn wacht op een nieuwe puls, echter de ontvanger voert zelf daarna nog 7 of meerdere pulsen uit.
Dus de tijd is ruim aanwezig en dit geeft gelijk de juiste timing in het geheel.
PWM_Value = map(input_PWM, 1090, 1950,1,30);
PWM_Value = map(PWM_Value, 1,30,1090,1950);
// MultiChannels
//
// rcarduino.blogspot.com
//
// A simple approach for reading three RC Channels using pin change interrupts
//
// See related posts -
// http://rcarduino.blogspot.co.uk/2012/01/how-to-read-rc-receiver-with.html
// http://rcarduino.blogspot.co.uk/2012/03/need-more-interrupts-to-read-more.html
// http://rcarduino.blogspot.co.uk/2012/01/can-i-control-more-than-x-servos-with.html
//
// rcarduino.blogspot.com
//
// include the pinchangeint library - see the links in the related topics section above for details
#include <PinChangeInt.h>
#include <Adafruit_MotorShield.h> // Library Motor/Stepper shield
#include <Servo.h> // remove l8ther if not needed
#include <Wire.h> // i2c bus
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
Adafruit_MotorShield AFMS1 = Adafruit_MotorShield(0x60); // Adafruit motorshield 1 on (0x60)
Adafruit_StepperMotor *Whouse_Lift = AFMS1.getStepper(200, 1); // motor 1 200 steps/rev on shield 1
Adafruit_StepperMotor *Winch = AFMS1.getStepper(64, 2); // motor 2 64 steps/rev on shield 1
// pwm output on pins 3.5.6.9.10.11 Nano /UNO
// Digital input on pins 2.4.7.8.12.13
// Assign your channel in pins
#define RStick_UD_IN_PIN 4
#define RStick_TURN_IN_PIN 7
#define Flaps_IN_PIN 2
#define Gear_IN_PIN 8 //Decoupler
#define Whouse_Bottom_IN_PIN A1
#define Whouse_Top_IN_PIN A2
// Assign your channel out pins
#define Firemon_Pump_OUT_Pin 3 //placeholder should the pump be run by an ESC
#define Firemon_Turn_OUT_PIN 5 // otherwise pump should be run by motorshield
#define RStick_UD_OUT_PIN 3
#define RStick_TURN_OUT_PIN 5
#define Flaps_OUT_PIN 6
#define Gear_OUT_PIN 9 //Decoupler
//Define Limmits
#define Firemon_Turn_UL 1725 // Left (UpperLimit)
#define Firemon_Turn_LL 1305 // Right (LowerLimit)
#define Firemon_Pump_UL 1725
#define Firemon_Pump_LL 1305
#define Whouse_UL 1725
#define Whouse_LL 1305
#define Crane_Turn_UL 1725
#define Crane_Turn_LL 1305
#define Crane_Arm_UL 1725
#define Crane_Arm_LL 1305
#define Decoupler_UL 1725
#define Decoupler_LL 1305
#define RStickUD_UL 1900 // define Rightstick limits
#define RStickUD_LL 1100
#define RStickRL_UL 1900 // define Rightstick limits
#define RStickRL_LL 1120
#define RStick_Center_UL 1545
#define RStick_Center_LL 1505
#define Flaps_ON 1900
#define Flaps_OFF 1100
#define Gear_ON 1900
#define Gear_OFF 1100
// Set RStick_modes. selected by txflaps 1 and setting RStick. Choice recorded by txflaps to 0
#define Fire_Monitor 1 // Top Left
#define Crane 2 // Top Right
#define Tow_Winch 3 // Bottom Right
#define Light_Radar_Whouse 4 // Bottom Left
int RStick_Mode = 0;
int Active = 0;
int Do_Step=0;
int steps = 200;
int step_direction = BACKWARD;
int reel_out = 0;
int lastButtonState = LOW; // the previous reading from the input pin
int Whouse_Lift_Top = LOW; // What is the State of the Endswitches of the Whouse
int Whouse_Lift_Bottom = LOW;
int Set_Pump = 0;
int Stick_Pos = 0;
int RStickUD = 0;
int RStickRL = 0;
int reel_locked=1;
// Servo objects generate the signals expected by Electronic Speed Controllers and Servos
// We will use the objects to output the signals we read in
// this example code provides a straight pass through of the signal with no custom processing
Servo servoFiremon_Pump;
Servo servoFiremon_Turn;
Servo servoRStick_UD;
Servo servoRStick_TURN;
Servo servoFlaps;
Servo servoGear;
Servo servoCrane_Arm;
Servo servoCrane_Turn;
// These bit flags are set in bUpdateFlagsShared to indicate which
// channels have new signals
#define RStick_UD_FLAG 1
#define RStick_TURN_FLAG 2
#define Flaps_FLAG 4
#define Gear_FLAG 8
// holds the update flags defined above
volatile uint8_t bUpdateFlagsShared;
// shared variables are updated by the ISR and read by loop.
// In loop we immediatley take local copies so that the ISR can keep ownership of the
// shared ones. To access these in loop
// we first turn interrupts off with noInterrupts
// we take a copy to use in loop and the turn interrupts back on
// as quickly as possible, this ensures that we are always able to receive new signals
volatile uint16_t unRStick_UDInShared;
volatile uint16_t unRStick_TURNInShared;
volatile uint16_t unFlapsInShared;
volatile uint16_t unGearInShared;
// These are used to record the rising edge of a pulse in the calcInput functions
// They do not need to be volatile as they are only used in the ISR. If we wanted
// to refer to these in loop and the ISR then they would need to be declared volatile
uint32_t ulRStick_UDStart;
uint32_t ulRStick_TURNStart;
uint32_t ulFlapsStart;
uint32_t ulGearStart;
void setup()
{
Serial.begin(9600);
Serial.println("multiChannels");
Wire.begin() ; // Start I2C
lcd.begin(20,4); // Start LCD
// attach servo objects, these will generate the correct
// pulses for driving Electronic speed controllers, servos or other devices
// designed to interface directly with RC Receivers
servoRStick_UD.attach(RStick_UD_OUT_PIN);
servoRStick_TURN.attach(RStick_TURN_OUT_PIN);
servoFlaps.attach(Flaps_OUT_PIN);
servoGear.attach(Gear_OUT_PIN);
servoFiremon_Pump.attach(Firemon_Pump_OUT_Pin);
AFMS1.begin(); // create stepper instance with the default frequency 1.6KHz on Shield 1
Whouse_Lift->setSpeed(60); // 60 rpm
Winch->setSpeed(60);
// using the PinChangeInt library, attach the interrupts
// used to read the channels
PCintPort::attachInterrupt(RStick_UD_IN_PIN, calcRStick_UD,CHANGE);
PCintPort::attachInterrupt(RStick_TURN_IN_PIN, calcRStick_TURN,CHANGE);
PCintPort::attachInterrupt(Flaps_IN_PIN, calcFlaps,CHANGE);
PCintPort::attachInterrupt(Gear_IN_PIN, calcGear,CHANGE);
}
void loop()
{
// create local variables to hold a local copies of the channel inputs
// these are declared static so that thier values will be retained
// between calls to loop.
static uint16_t unRStick_UDIn;
static uint16_t unRStick_TURNIn;
static uint16_t unFlapsIn;
static uint16_t unGearIn;
// local copy of update flags
static uint8_t bUpdateFlags;
// check shared update flags to see if any channels have a new signal
if(bUpdateFlagsShared)
{
noInterrupts(); // turn interrupts off quickly while we take local copies of the shared variables
// take a local copy of which channels were updated in case we need to use this in the rest of loop
bUpdateFlags = bUpdateFlagsShared;
// in the current code, the shared values are always populated
// so we could copy them without testing the flags
// however in the future this could change, so lets
// only copy when the flags tell us we can.
if(bUpdateFlags & RStick_UD_FLAG)
{
unRStick_UDIn = unRStick_UDInShared;
}
if(bUpdateFlags & RStick_TURN_FLAG)
{
unRStick_TURNIn = unRStick_TURNInShared;
}
if(bUpdateFlags & Flaps_FLAG)
{
unFlapsIn = unFlapsInShared;
}
if(bUpdateFlags & Gear_FLAG)
{
unGearIn = unGearInShared;
}
// clear shared copy of updated flags as we have already taken the updates
// we still have a local copy if we need to use it in bUpdateFlags
bUpdateFlagsShared = 0;
interrupts(); // we have local copies of the inputs, so now we can turn interrupts back on
// as soon as interrupts are back on, we can no longer use the shared copies, the interrupt
// service routines own these and could update them at any time. During the update, the
// shared copies may contain junk. Luckily we have our local copies to work with :-)
}
// do any processing from here onwards
// only use the local values unFlapsIn, unRStick_UDIn and unRStick_TURNIn, the shared
// variables unFlapsInShared, unRStick_UDInShared, unRStick_TURNInShared are always owned by
// the interrupt routines and should not be used in loop
// we are checking to see if the channel value has changed, this is indicated
// by the flags. For the simple pass through we don't really need this check,
// but for a more complex project where a new signal requires significant processing
// this allows us to only calculate new values when we have new inputs, rather than
// on every cycle.
if(bUpdateFlags & RStick_UD_FLAG)
{
if(servoRStick_UD.readMicroseconds() != unRStick_UDIn)
{
Stick_Pos = servoRStick_UD.readMicroseconds();
// servoRStick_UD.writeMicroseconds(unRStick_UDIn);
switch (RStick_Mode)
{
case Fire_Monitor:
Set_Pump = map(Stick_Pos,RStick_Center_UL,RStickUD_UL,Firemon_Pump_LL,Firemon_Pump_UL) ;
servoFiremon_Pump.writeMicroseconds(Set_Pump); // (1/2 stick (start at +10%)throw needs mapping to full pump)
break;
case Crane:
if( Stick_Pos > Crane_Arm_LL & Stick_Pos < Crane_Arm_UL) //limits
{
servoCrane_Arm.writeMicroseconds(servoRStick_UD.readMicroseconds()); // Direct drive
} // endif limits
break;
case Light_Radar_Whouse:
RStickUD = servoRStick_UD.readMicroseconds();
RStickRL = servoRStick_TURN.readMicroseconds();
// Whouse_Lift
Read_Whouse_End_switches();
if (RStickUD > RStick_Center_UL & RStickUD <= 1641 & Whouse_Lift_Top != HIGH) { Do_Step=1; Whouse_Lift->setSpeed(10);step_direction = FORWARD;} // 1/4 stick
if (RStickUD > RStick_Center_UL & RStickUD <= 1737 & Whouse_Lift_Top != HIGH) { Do_Step=1; Whouse_Lift->setSpeed(20);step_direction = FORWARD;} // 1/2 stick
if (RStickUD > RStick_Center_UL & RStickUD <= 1833 & Whouse_Lift_Top != HIGH) { Do_Step=1; Whouse_Lift->setSpeed(40);step_direction = FORWARD;} // 3/4 stick
if (RStickUD > RStick_Center_UL & RStickUD <= RStickRL_UL & Whouse_Lift_Top != HIGH) { Do_Step=1; Whouse_Lift->setSpeed(60);step_direction = FORWARD;} // full+96 stick
if (RStickUD < RStick_Center_LL & RStickUD >= 1402 & Whouse_Lift_Bottom != HIGH) { Do_Step=1; Whouse_Lift->setSpeed(10);step_direction = BACKWARD;} // - 1/4 stick
if (RStickUD < RStick_Center_LL & RStickUD >= 1299 & Whouse_Lift_Bottom != HIGH) { Do_Step=1; Whouse_Lift->setSpeed(20);step_direction = BACKWARD;} // - 1/2 stick
if (RStickUD < RStick_Center_LL & RStickUD >= 1196 & Whouse_Lift_Bottom != HIGH) { Do_Step=1; Whouse_Lift->setSpeed(40);step_direction = BACKWARD;} // - 3/4 stick
if (RStickUD < RStick_Center_LL & RStickUD >= RStickRL_LL & Whouse_Lift_Bottom != HIGH) { Do_Step=1; Whouse_Lift->setSpeed(60);step_direction = BACKWARD;} // - full stick
// Do we need to step?
if (Do_Step == 1)
{
Whouse_Lift->step(steps, step_direction, MICROSTEP); //DOUBLE/SINGLE/MICROSTEP
Whouse_Lift->release(); //Brakes off eg power off Steppermotor
}
break;
case Tow_Winch:
if (Stick_Pos > RStick_Center_LL & Stick_Pos < RStick_Center_UL & reel_locked == 0) {Winch->step(1, FORWARD, MICROSTEP); reel_locked=1;} // Lock reel
if (Stick_Pos > RStick_Center_UL & Stick_Pos <= 1641 ) { Do_Step=1; Winch->setSpeed(10);step_direction = FORWARD;} // 1/4 stick
if (Stick_Pos > RStick_Center_UL & Stick_Pos <= 1737 ) { Do_Step=1; Winch->setSpeed(20);step_direction = FORWARD;} // 1/2 stick
if (Stick_Pos > RStick_Center_UL & Stick_Pos <= 1833 ) { Do_Step=1; Winch->setSpeed(30);step_direction = FORWARD;} // 3/4 stick
if (Stick_Pos > RStick_Center_UL & Stick_Pos <= RStickRL_UL ) { Do_Step=1; Winch->setSpeed(40);step_direction = FORWARD;} // full+96 stick
if (Stick_Pos < RStick_Center_LL & Stick_Pos >= 1402 ) { Do_Step=0; reel_out = 1; reel_locked = 0;} // - 1/4 stick
if (Stick_Pos < RStick_Center_LL & Stick_Pos >= 1299 ) { Do_Step=1; Winch->setSpeed(10);step_direction = BACKWARD;} // - 1/2 stick
if (Stick_Pos < RStick_Center_LL & Stick_Pos >= 1196 ) { Do_Step=1; Winch->setSpeed(20);step_direction = BACKWARD;} // - 3/4 stick
if (Stick_Pos < RStick_Center_LL & RStickUD >= RStickRL_LL ) { Do_Step=1; Winch->setSpeed(30);step_direction = BACKWARD;} // - full stick
// Do we need to step?
if (Do_Step == 1) {Winch->step(steps, step_direction, MICROSTEP); reel_locked=1;} //DOUBLE/SINGLE/MICROSTEP
if (reel_out == 1) {Winch->release();} //Brakes off eg power off Steppermotor
break;
default:
break;
}
}
}
if(bUpdateFlags & RStick_TURN_FLAG)
{
if(servoRStick_TURN.readMicroseconds() != unRStick_TURNIn)
{
servoRStick_TURN.writeMicroseconds(unRStick_TURNIn);
}
}
if(bUpdateFlags & Gear_FLAG)
{
if(servoGear.readMicroseconds() != unGearIn)
{
servoGear.writeMicroseconds(unGearIn);
}
}
if(bUpdateFlags & Flaps_FLAG)
{
// if(servoFlaps.readMicroseconds() != unFlapsIn)
// {
lcd.setCursor ( 0, 0 );
lcd.print("RS_Mode =");
lcd.setCursor ( 0, 1 );
if (unFlapsIn > Flaps_ON)
{
Active = 0;
if (unRStick_UDIn > RStickUD_UL & unRStick_TURNIn > RStickRL_UL) {lcd.print("Firemonitor ");RStick_Mode = Fire_Monitor;} // Stick is Top Left
if (unRStick_UDIn > RStickUD_UL & unRStick_TURNIn < RStickRL_LL) {lcd.print("Crane ");RStick_Mode = Crane;} // Stick is Top Right
if (unRStick_UDIn < RStickUD_LL & unRStick_TURNIn > RStickRL_UL) {lcd.print("Lights_Radar_Whouse");RStick_Mode = Light_Radar_Whouse;}// Stick is Bottom Left
if (unRStick_UDIn < RStickUD_LL & unRStick_TURNIn < RStickRL_LL) {lcd.print("Winch ");RStick_Mode = Tow_Winch;} // Stick is Bottom Right
lcd.setCursor ( 0, 2 );
lcd.print(unRStick_UDIn);
lcd.setCursor ( 0, 3 );
lcd.print(unRStick_TURNIn);
lcd.setCursor ( 11, 0 );
lcd.print("IN-Act");
} // Endif Flaps_ON
// } // endif servoFlaps
} // endif Flaps update
// Run Selected mode. Active is true if Right Stick is centered after Flaps becomes 0
if (unFlapsIn < Flaps_OFF & !Active) // Wait for RStick Center
{
if (unRStick_UDIn >= RStick_Center_LL & unRStick_UDIn <= RStick_Center_UL) // up-Down is Centered and..// RStick is Centered ------>Activate !!...
{
if (unRStick_TURNIn >= RStick_Center_LL & unRStick_TURNIn <= RStick_Center_UL)
{
Active=1;
lcd.setCursor ( 11, 0 );
lcd.print("Act ");
}
}
} // Endif Activate
bUpdateFlags = 0;
} // End---LOOP
// Smooth-out input from reciever
int clean_PWM(int PWM_Value)
{
PWM_Value = map(PWM_Value,1040,1950,0,29);
PWM_Value = map(PWM_Value,0,29,1040,1950);
return PWM_Value;
}
void Read_Whouse_End_switches() // could need debouncing
{
Whouse_Lift_Top = digitalRead(Whouse_Bottom_IN_PIN); // What is the State of the Endswitches of the Whouse
Whouse_Lift_Bottom = digitalRead(Whouse_Top_IN_PIN);
}
// simple interrupt service routine
void calcRStick_UD()
{
// if the pin is high, its a rising edge of the signal pulse, so lets record its value
if(digitalRead(RStick_UD_IN_PIN) == HIGH)
{
ulRStick_UDStart = micros();
}
else
{
// else it must be a falling edge, so lets get the time and subtract the time of the rising edge
// this gives use the time between the rising and falling edges i.e. the pulse duration.
unRStick_UDInShared = (uint16_t)(micros() - ulRStick_UDStart);
// use set the RStick_UD flag to indicate that a new RStick_UD signal has been received
bUpdateFlagsShared |= RStick_UD_FLAG;
}
}
void calcRStick_TURN()
{
if(digitalRead(RStick_TURN_IN_PIN) == HIGH)
{
ulRStick_TURNStart = micros();
}
else
{
unRStick_TURNInShared = (uint16_t)(micros() - ulRStick_TURNStart);
bUpdateFlagsShared |= RStick_TURN_FLAG;
}
}
void calcFlaps()
{
if(digitalRead(Flaps_IN_PIN) == HIGH)
{
ulFlapsStart = micros();
}
else
{
unFlapsInShared = (uint16_t)(micros() - ulFlapsStart);
bUpdateFlagsShared |= Flaps_FLAG;
}
}
void calcGear()
{
if(digitalRead(Gear_IN_PIN) == HIGH)
{
ulGearStart = micros();
}
else
{
unGearInShared = (uint16_t)(micros() - ulGearStart);
bUpdateFlagsShared |= Gear_FLAG;
}
}
ROERWERK
Het werkt inmiddels.
Dat het eerst niet werkte was omdat ik pin 0 gebruikte en zoals je weet test ik op de Uno.
Dus gewisseld naar pin 3, die wel PWM heeft...
Helaas blijven de servo's jutteren en brommen. Maar de eind afstelling is per servo, per kant te regelen.
Langzaam het script uitbreiden dus...
De Monitor uitlezen resulteerd in het volgende:
Stick op nul RX_in = 1492 / 1514
Stick links RX_in = 1936 / 1959
Stick rechts RX_in = 1086 / 1108
Als ik de ontvanger of de zender uitzet, gaan de beide servo's meer dan 90 graden dwars.
Dat is iets dat in mijn boot dus niet mag gebeuren !!!
Is dit op te lossen door buiten de RX_min en RX_max uit de ontvanger de servo's automatisch in de midden te zetten?
Dus als een soort failsave reageerd hij niet buiten de ontvangerwaarden.
Of anders door de maximum grenzen van de servo's op de arduino duidelijk vast te stellen.
Een goede dag ik zit het met het zelfde probleemEindelijk de Arduino Nano binnen.
Gister getest op een breadboard.
Vandaag op een printplaatje geplaatst en voorzien van 3*3 aansluit pennen voor de ontvanger en de 2 servos.
De ontvanger gaat zijn stroom dus ook via deze print krijgen, de ontvanger en servos krijgen 6 volt via de groene aansluiting, via een glaszekering.
De nano wordt gevoed door 5 volt, op diezelfde groene schroefklem. De middelste aansluiting daarvan is gezamenlijke - (ground) ook via een glaszekering.
![]()
![]()
Een goedendag ik zie dat jij een heftconstructie hebt gemaakt voor de mast stuurhut ik zou graag meer info van willen hebben zo dat ik dit probleem waar ik tegen aanloop kan tekkelenHEFMAST
Over naar het hef gedeelte.
Dit bestaat in het origineel uit een 10 Tons 3traps heftruckmast met vrije heffing.
Vrije heffing houdt in dat eerst de vorken, (in dit geval de stuurhut) omhoog gaan en dan pas de mast. Anders gaat alles geleidelijk maar komt de mast boven de stuurhut uit.
Ik had lange tijd geen idee hoe ik het moest maken maar ben met messing h-profielen en 4mm. kogellagertjes aan het solderen geslagen.
Ik heb nu 2 gangen die in elkaar en de onderste vaste gang schuiven.
![]()
De bovenste gang is nog open aan de bovenste voorkant. Nu kan ik de stuurhut ophanging gaan maken met lagertjes die er van boven in gestoken kan worden.
Door de zekeringen kan ik nu wel makkelijk testen en op de pc laten draaien of stand alone op de eigen 5v. Voeding.
Wel valt het me op dat het zenuwachtig gedrag van de servos op de eigen voeding minder is dan met de usb als voeding.
Ik heb ook even geëxperimenteerd door het zenden naar de seriële monitor even uit het programma te halen. Dan heeft de nano minder werk, zie het aan het TX lampje.
Maar verder maakt dat ook geen verschil.
De roeren blijven onrustig. Dat dat in het inkomende signaal zit blijkt aan de output van de seriële monitor dus doet de nano gewoon zijn werk.
Als ik de servo direct in de ontvanger plug, zie ik geen enkel misstapje. Wel is het zo dat dan de servo maar de helft van de uitslag heeft, dus elke kleine beweging wordt sowieso dubbel zo groot in de nano.
Uiteindelijk moet er nog een failsave en een Servo delay in. Daar kan ook nog wat met het signaal gedaan worden om het rustig te krijgen.