The method described here is an example of combining individual technologies.
The Wii Remote's sensors were not designed for RC use. The craft can become uncontrollable and fly off in unexpected directions or crash.
Flight regulations aside, careless flying is extremely dangerous. Please exercise extreme caution.
Progress on this series has been painfully slow, and in the meantime drone regulations have been introduced — leaving me wondering where you'd even fly this thing anymore. But let's press on anyway.
Last time, I covered implementing safety features in Arduino.
This time, I'll finish the remaining Arduino code to enable full Wii Remote control.
Check on Amazon The Wii Remote used here is a standard one with MotionPlus.
I originally wanted to use the Classic Controller for analog input, but I couldn't get Arduino to recognize it.
The Nunchuk is recognized, but it kept disconnecting during use, making it unusable.
Check on Amazon There's a PS3 controller library for Arduino, so a PS3 DUALSHOCK 3 might give you better control than the Wii Remote — though this code wouldn't work as-is.
Full source code
The source code is on GitHub:
https://github.com/onthehand/Quad_PPM/blob/master/Quad_PPM.ino
Most of the code has been explained in previous posts, so let me walk through the
loop function as a recap.Wii Remote connection check
Check whether the remote is connected. If not connected, do nothing.
void loop() {
Usb.Task();
if(! Wii.wiimoteConnected || Wii.getButtonPress(HOME)){ activate = 0; return; }
Check the accelerometer at regular intervals.
If the value matches the previous check, increment
cc. If cc exceeds a threshold, disarm.See Safety Feature #1 from the previous post for details.
Using a hardware watchdog timer to reset on a timeout would be more elegant, but I didn't want to add more interrupts — so this is a slightly inelegant solution.
if( millis() > uptime ){
// check connection
if( pp == Wii.getPitch() && pr == Wii.getRoll() ){ cc ++ ; }else{ cc = 0; }
pp = Wii.getPitch();
pr = Wii.getRoll();
if(Wii.getButtonPress(RIGHT)){
currentTh++;
}else if(Wii.getButtonPress(LEFT)){
currentTh--;
}
uptime = millis() + SPAN;
}
if ( cc > WII_TIMEOUT / SPAN ){ activate = 0; return; }
activate = 1;
The RIGHT button increments the throttle (
currentTh); LEFT decrements it.Why RIGHT/LEFT instead of UP/DOWN? Because the remote is held sideways. When held sideways, RIGHT faces up.
The throttle acceleration when holding the button is controlled by the
SPAN variable — which is also shared with the connection-check interval. So reducing throttle responsiveness also makes the connection-loss detection slower. Messy.Camera control
See the earlier post about camera control for context.
Pressing the "2" button sends a pulse to the camera:
if( 0 < camtrig && camtrig < millis() ){
camtrig = 0;
digitalWrite( PIN_CAMERA, LOW );
}
if( camtrig == 0 && Wii.getButtonPress(TWO) ){
camtrig = millis() + CAMERA_PULSE;
digitalWrite( PIN_CAMERA, HIGH );
}
Roll / Pitch / Yaw control
The code is getting chaotic, but here we go.
y, r, and p are the Yaw, Roll, and Pitch variables.Yaw is directional turning, so I simply mapped it to the UP/DOWN buttons (which become left/right when holding the remote sideways).
checkButton just returns a value based on which button is pressed:- DOWN button → HIGH_PULSE_TIME (Yaw right)
- UP button → LOW_PULSE_TIME (Yaw left)
- Neither → HALF_PULSE_TIME (Yaw centered)
Roll and Pitch are derived from the accelerometer values, scaled to MultiWii's pulse width range.
The variable assignments may look backwards, but that's due to holding the remote sideways.
On the Wii Remote, "Roll" is rotation around the long axis. When held sideways, forward/backward tilting corresponds to Roll rotation — but on the quadcopter, that maps to Pitch (nose up/down). Complex.
unsigned int y = checkButton(DOWN,UP,HIGH_PULSE_TIME,HALF_PULSE_TIME,LOW_PULSE_TIME); unsigned int r = map((unsigned int)(Wii.getPitch()*100.0), 9000, 27000, MAX_PULSE_TIME, MIN_PULSE_TIME); unsigned int p = map((unsigned int)(Wii.getRoll()*100.0), 9000, 27000, MIN_PULSE_TIME, MAX_PULSE_TIME);
Bonus feature: AUX channels
Pressing the "1" button sets MultiWii's AUX1 HIGH.
AUX1 and AUX2 correspond to the toggle switches found on a real radio transmitter.
If you assign BARO to AUX1 on the MultiWii side, you can toggle the barometric altitude hold on and off from the Wii Remote.
BARO is the barometer. When enabled, it uses the pressure sensor to automatically maintain altitude... in theory. In practice, the error is too large to rely on.
AUX2 is set up but not actually used. MultiWii has a feature for triggering the camera via AUX2, but since MultiWii is already interrupt-sensitive, I decided it's safer and more reliable to trigger the camera directly from the Arduino side instead.
// BARO is supposed to be activated by AUX1.
unsigned int a1 = (Wii.getButtonPress(ONE)) ? HIGH_PULSE_TIME : HALF_PULSE_TIME;
unsigned int a2 = (Wii.getButtonPress(TWO)) ? HIGH_PULSE_TIME : HALF_PULSE_TIME;
if( Wii.getWiiState() & 0x01 ){ a2 = LOW_PULSE_TIME; }
ARM / DISARM
Normally ARM and DISARM are performed by a specific combination of stick positions on a standard transmitter — which is impossible to replicate with a Wii Remote. So I implemented shortcuts instead.
I mapped ARM and DISARM to B + Plus and B + Minus respectively — combinations impossible to trigger accidentally:
if(Wii.getButtonPress(B)){
r = p = HALF_PULSE_TIME;
if(Wii.getButtonPress(PLUS)){
// arm
currentTh = 1000;
y = 2000;
}else if(Wii.getButtonPress(MINUS)){
// disarm
currentTh = y = 1000;
}
}
}
Check on Amazon
So in theory, I've replicated a proper radio transmitter that normally costs tens of thousands of yen — with a Wii Remote costing a few thousand.
…except it doesn't really work that well.
The Wii Remote's Bluetooth range is only about 10 meters, so fly a little too far and the connection drops instantly.
Even within 10 meters, disconnections happen frequently, making it genuinely dangerous. Practical use is basically zero.
Never underestimate a proper Futaba transmitter.
Next time: the MultiWii side of things.
If I feel like it.
No comments:
Post a Comment