Download:
child 1:bf539ff23816
0:d3c896ca5a17
Anton Shestakov <engored@ya.ru>, Sun, 13 Oct 2013 13:14:35 +0900
Basics.

6 файлов изменено, 502 вставок(+), 0 удалений(-) [+]
README.rst file | annotate | diff | comparison | revisions
car2wd_bt/car2wd_bt.ino file | annotate | diff | comparison | revisions
chukmote.fzz file | annotate | diff | comparison | revisions
chukmote.py file | annotate | diff | comparison | revisions
chukmote/WiiChuck.h file | annotate | diff | comparison | revisions
chukmote/chukmote.ino file | annotate | diff | comparison | revisions
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/README.rst Sun Oct 13 13:14:35 2013 +0900
@@ -0,0 +1,13 @@
+Wiring diagram
+==============
+
+See chukmote.fzz or `chuckmote_bb.svg
+<https://bitbucket.org/engored/chukmote/raw/tip/chukmote_bb.svg>`_.
+
+
+Parts list
+==========
+
+- WiiChuck Adapter for Arduino: https://dx.com/p/147094
+- L298N Motor Board: https://dx.com/p/120542
+- Bluetooth Serial Port Module: https://dx.com/p/104299
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/car2wd_bt/car2wd_bt.ino Sun Oct 13 13:14:35 2013 +0900
@@ -0,0 +1,53 @@
+#include <VirtualWire.h>
+
+#define IN1 3
+#define IN2 5
+#define IN3 6
+#define IN4 11
+
+
+unsigned long lastmsg = 0;
+int lspd = 0, rspd = 0;
+
+
+void setup() {
+ Serial.begin(9600);
+
+ pinMode(IN1, OUTPUT);
+ pinMode(IN2, OUTPUT);
+ pinMode(IN3, OUTPUT);
+ pinMode(IN4, OUTPUT);
+}
+
+
+void loop() {
+ if (Serial.available() > 0) {
+ int a = Serial.parseInt();
+ int b = Serial.parseInt();
+ if (Serial.read() == '\n') {
+ lspd = a;
+ rspd = b;
+ lastmsg = millis();
+ }
+ } else {
+ unsigned int fade = (millis() - lastmsg) / 1000;
+ //lspd /= fade;
+ //rspd /= fade;
+ }
+
+ if (lspd > 0) {
+ analogWrite(IN3, map(lspd, 0, 127, 0, 255));
+ digitalWrite(IN4, LOW);
+ } else {
+ digitalWrite(IN3, LOW);
+ analogWrite(IN4, map(lspd, 0, -128, 0, 255));
+ }
+
+ if (rspd > 0) {
+ analogWrite(IN1, map(rspd, 0, 127, 0, 255));
+ digitalWrite(IN2, LOW);
+ } else {
+ digitalWrite(IN1, LOW);
+ analogWrite(IN2, map(rspd, 0, -128, 0, 255));
+ }
+}
Binary file chukmote.fzz has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chukmote.py Sun Oct 13 13:14:35 2013 +0900
@@ -0,0 +1,162 @@
+#!/usr/bin/env python3
+import atexit
+import curses
+import sys
+
+
+class UI:
+ def init(self):
+ self.stdscr = curses.initscr()
+ curses.noecho()
+ curses.cbreak()
+ curses.curs_set(0)
+ self.stdscr.keypad(1)
+
+ self.nubwin = self.stdscr.subwin(9, 17, 2, 4)
+ self.inwin = self.stdscr.subwin(10, 20, 2, 23)
+ self.lthwin = self.stdscr.subwin(9, 4, 2, 45)
+ self.rthwin = self.stdscr.subwin(9, 4, 2, 50)
+ self.outwin = self.stdscr.subwin(10, 20, 2, 56)
+
+ def draw(self):
+ self.stdscr.box()
+
+ self.nubwin.box()
+
+ self.inwin.box()
+ self.inwin.addstr(0, 1, ' Input ')
+ self.inwin.addstr(2, 4, 'Nub X:')
+ self.inwin.addstr(3, 4, 'Nub Y:')
+ self.inwin.addstr(4, 4, 'Pitch:')
+ self.inwin.addstr(5, 4, 'Roll:')
+ self.inwin.addstr(6, 4, 'C:')
+ self.inwin.addstr(7, 4, 'Z:')
+
+ self.lthwin.box()
+ self.rthwin.box()
+
+ self.outwin.box()
+ self.outwin.addstr(0, 1, ' Output ')
+ self.outwin.addstr(2, 4, 'Left:')
+ self.outwin.addstr(3, 4, 'Right:')
+
+ self.stdscr.refresh()
+
+ def update(self, rawinput, lspd, rspd):
+ self.inwin.addstr(2, 10, '{0:5}'.format(rawinput.x))
+ self.inwin.addstr(3, 10, '{0:5}'.format(rawinput.y))
+ self.inwin.addstr(4, 10, '{0:5}'.format(rawinput.pitch))
+ self.inwin.addstr(5, 10, '{0:5}'.format(rawinput.roll))
+ self.inwin.addstr(6, 8, 'on ' if rawinput.c else 'off')
+ self.inwin.addstr(7, 8, 'on ' if rawinput.z else 'off')
+ self.inwin.refresh()
+
+ self.nubwin.erase()
+ self.nubwin.box()
+ self.nubwin.addch(4 - round(rawinput.y / 42), 8 + round(rawinput.x / 21), 'o')
+ self.nubwin.refresh()
+
+ self.lthwin.erase()
+ self.lthwin.box()
+ llim = 4 - round(lspd / 42)
+ for i in range(min(llim, 4), max(llim, 4) + 1):
+ self.lthwin.addstr(i, 1, ' ', curses.A_REVERSE)
+ self.lthwin.refresh()
+
+ self.rthwin.erase()
+ self.rthwin.box()
+ rlim = 4 - round(rspd / 42)
+ for i in range(min(rlim, 4), max(rlim, 4) + 1):
+ self.rthwin.addstr(i, 1, ' ', curses.A_REVERSE)
+ self.rthwin.refresh()
+
+ self.outwin.addstr(2, 10, '{0:5}'.format(lspd))
+ self.outwin.addstr(3, 10, '{0:5}'.format(rspd))
+ self.outwin.refresh()
+
+ def error(self, error):
+ self.stdscr.addstr(22, 2, error)
+ self.stdscr.refresh()
+
+ def finish(self):
+ self.stdscr.keypad(0)
+
+ curses.nocbreak()
+ curses.echo()
+ curses.endwin()
+
+
+class Driver:
+ deadzone = 10
+ lspd = 0
+ rspd = 0
+
+ def update(self, rawinput):
+ self.lspd = 0
+ self.rspd = 0
+
+ if abs(rawinput.y) > self.deadzone:
+ self.lspd = rawinput.y
+ self.rspd = rawinput.y
+
+ if abs(rawinput.x) > self.deadzone:
+ self.lspd += rawinput.x
+ self.rspd -= rawinput.x
+
+ if self.lspd < -128: self.lspd = -128
+ if self.lspd > 127: self.lspd = 127
+ if self.rspd < -128: self.rspd = -128
+ if self.rspd > 127: self.rspd = 127
+
+
+class RawInput:
+ def __init__(self, x=0, y=0, pitch=0, roll=0, c=False, z=False):
+ self.x = x
+ self.y = y
+ self.pitch = pitch
+ self.roll = roll
+ self.c = c
+ self.z = z
+
+
+def decode_input(line):
+ parts = line.strip().split(',')
+ x = int(parts[0])
+ y = int(parts[1])
+ pitch = int(parts[2])
+ roll = int(parts[3])
+ c = parts[4] == 'C'
+ z = parts[5] == 'Z'
+ return RawInput(x, y, pitch, roll, c, z)
+
+
+def encode_output(lspd, rspd):
+ return '{0},{1}\n'.format(lspd, rspd)
+
+
+def main():
+ tty_in = open(sys.argv[1], 'rb', 0)
+ tty_out = open(sys.argv[2], 'wb', 0)
+
+ driver = Driver()
+ ui = UI()
+
+ ui.init()
+ atexit.register(ui.finish)
+ ui.draw()
+
+ with tty_in, tty_out:
+ while True:
+ try:
+ line = tty_in.readline().decode()
+ rawinput = decode_input(line)
+ except (IndexError, ValueError):
+ ui.error('bad line "{0}"'.format(line.strip('\n')))
+ else:
+ driver.update(rawinput)
+ ui.update(rawinput, driver.lspd, driver.rspd)
+ tty_out.write(encode_output(driver.lspd, driver.rspd).encode())
+
+
+if __name__ == '__main__':
+ main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chukmote/WiiChuck.h Sun Oct 13 13:14:35 2013 +0900
@@ -0,0 +1,228 @@
+/*
+ * Nunchuck -- Use a Wii Nunchuck
+ * Tim Hirzel http://www.growdown.com
+ *
+ notes on Wii Nunchuck Behavior.
+ This library provides an improved derivation of rotation angles from the nunchuck accelerometer data.
+ The biggest different over existing libraries (that I know of ) is the full 360 degrees of Roll data
+ from teh combination of the x and z axis accelerometer data using the math library atan2.
+
+ It is accurate with 360 degrees of roll (rotation around axis coming out of the c button, the front of the wii),
+ and about 180 degrees of pitch (rotation about the axis coming out of the side of the wii). (read more below)
+
+ In terms of mapping the wii position to angles, its important to note that while the Nunchuck
+ sense Pitch, and Roll, it does not sense Yaw, or the compass direction. This creates an important
+ disparity where the nunchuck only works within one hemisphere. At a result, when the pitch values are
+ less than about 10, and greater than about 170, the Roll data gets very unstable. essentially, the roll
+ data flips over 180 degrees very quickly. To understand this property better, rotate the wii around the
+ axis of the joystick. You see the sensor data stays constant (with noise). Because of this, it cant know
+ the difference between arriving upside via 180 degree Roll, or 180 degree pitch. It just assumes its always
+ 180 roll.
+
+
+ *
+ * This file is an adaptation of the code by these authors:
+ * Tod E. Kurt, http://todbot.com/blog/
+ *
+ * The Wii Nunchuck reading code is taken from Windmeadow Labs
+ * http://www.windmeadow.com/node/42
+ *
+ * Conversion to Arduino 1.0 by Danjovic
+ * http://hotbit.blogspot.com
+ *
+ */
+
+#ifndef WiiChuck_h
+#define WiiChuck_h
+
+
+#include "Arduino.h"
+#include <Wire.h>
+#include <math.h>
+
+
+// these may need to be adjusted for each nunchuck for calibration
+#define ZEROX 510
+#define ZEROY 490
+#define ZEROZ 460
+#define RADIUS 210 // probably pretty universal
+
+#define DEFAULT_ZERO_JOY_X 129
+#define DEFAULT_ZERO_JOY_Y 128
+
+
+
+class WiiChuck {
+ private:
+ uint8_t cnt;
+ uint8_t status[6]; // array to store wiichuck output
+ uint8_t averageCounter;
+ //int accelArray[3][AVERAGE_N]; // X,Y,Z
+ int i;
+ int total;
+ uint8_t zeroJoyX; // these are about where mine are
+ uint8_t zeroJoyY; // use calibrateJoy when the stick is at zero to correct
+ int lastJoyX;
+ int lastJoyY;
+ int angles[3];
+
+ bool lastZ, lastC;
+
+
+ public:
+
+ uint8_t joyX;
+ uint8_t joyY;
+ bool buttonZ;
+ bool buttonC;
+ void begin()
+ {
+ Wire.begin();
+ cnt = 0;
+ averageCounter = 0;
+ // instead of the common 0x40 -> 0x00 initialization, we
+ // use 0xF0 -> 0x55 followed by 0xFB -> 0x00.
+ // this lets us use 3rd party nunchucks (like cheap $4 ebay ones)
+ // while still letting us use official oness.
+ // only side effect is that we no longer need to decode bytes in _nunchuk_decode_byte
+ // see http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1264805255
+ //
+ Wire.beginTransmission(0x52); // device address
+ Wire.write(0xF0);
+ Wire.write(0x55);
+ Wire.endTransmission();
+ delay(1);
+ Wire.beginTransmission(0x52);
+ Wire.write(0xFB);
+ Wire.write((uint8_t)0x00);
+
+ Wire.endTransmission();
+ update();
+ for (i = 0; i<3;i++) {
+ angles[i] = 0;
+ }
+ zeroJoyX = DEFAULT_ZERO_JOY_X;
+ zeroJoyY = DEFAULT_ZERO_JOY_Y;
+ }
+
+
+ void calibrateJoy() {
+ zeroJoyX = joyX;
+ zeroJoyY = joyY;
+ }
+
+ void update() {
+
+ Wire.requestFrom (0x52, 6); // request data from nunchuck
+ while (Wire.available ()) {
+ // receive byte as an integer
+ status[cnt] = _nunchuk_decode_byte (Wire.read()); //
+ cnt++;
+ }
+ if (cnt > 5) {
+ lastZ = buttonZ;
+ lastC = buttonC;
+ lastJoyX = readJoyX();
+ lastJoyY = readJoyY();
+ //averageCounter ++;
+ //if (averageCounter >= AVERAGE_N)
+ // averageCounter = 0;
+
+ cnt = 0;
+ joyX = (status[0]);
+ joyY = (status[1]);
+ for (i = 0; i < 3; i++)
+ //accelArray[i][averageCounter] = ((int)status[i+2] << 2) + ((status[5] & (B00000011 << ((i+1)*2) ) >> ((i+1)*2)));
+ angles[i] = (status[i+2] << 2) + ((status[5] & (B00000011 << ((i+1)*2) ) >> ((i+1)*2)));
+
+ //accelYArray[averageCounter] = ((int)status[3] << 2) + ((status[5] & B00110000) >> 4);
+ //accelZArray[averageCounter] = ((int)status[4] << 2) + ((status[5] & B11000000) >> 6);
+
+ buttonZ = !( status[5] & B00000001);
+ buttonC = !((status[5] & B00000010) >> 1);
+ _send_zero(); // send the request for next bytes
+
+ }
+ }
+
+
+ // UNCOMMENT FOR DEBUGGING
+ //byte * getStatus() {
+ // return status;
+ //}
+
+ float readAccelX() {
+ // total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT;
+ return (float)angles[0] - ZEROX;
+ }
+ float readAccelY() {
+ // total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT;
+ return (float)angles[1] - ZEROY;
+ }
+ float readAccelZ() {
+ // total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT;
+ return (float)angles[2] - ZEROZ;
+ }
+
+ bool zPressed() {
+ return (buttonZ && ! lastZ);
+ }
+ bool cPressed() {
+ return (buttonC && ! lastC);
+ }
+
+ // for using the joystick like a directional button
+ bool rightJoy(int thresh=60) {
+ return (readJoyX() > thresh and lastJoyX <= thresh);
+ }
+
+ // for using the joystick like a directional button
+ bool leftJoy(int thresh=60) {
+ return (readJoyX() < -thresh and lastJoyX >= -thresh);
+ }
+
+
+ int readJoyX() {
+ return (int) joyX - zeroJoyX;
+ }
+
+ int readJoyY() {
+ return (int)joyY - zeroJoyY;
+ }
+
+
+ // R, the radius, generally hovers around 210 (at least it does with mine)
+ // int R() {
+ // return sqrt(readAccelX() * readAccelX() +readAccelY() * readAccelY() + readAccelZ() * readAccelZ());
+ // }
+
+
+ // returns roll degrees
+ int readRoll() {
+ return (int)(atan2(readAccelX(),readAccelZ())/ M_PI * 180.0);
+ }
+
+ // returns pitch in degrees
+ int readPitch() {
+ return (int) (acos(readAccelY()/RADIUS)/ M_PI * 180.0); // optionally swap 'RADIUS' for 'R()'
+ }
+
+ private:
+ uint8_t _nunchuk_decode_byte (uint8_t x)
+ {
+ //decode is only necessary with certain initializations
+ //x = (x ^ 0x17) + 0x17;
+ return x;
+ }
+
+ void _send_zero()
+ {
+ Wire.beginTransmission (0x52); // transmit to device 0x52
+ Wire.write ((uint8_t)0x00); // sends one byte
+ Wire.endTransmission (); // stop transmitting
+ }
+
+};
+
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chukmote/chukmote.ino Sun Oct 13 13:14:35 2013 +0900
@@ -0,0 +1,46 @@
+#include "Wire.h"
+#include "WiiChuck.h"
+
+
+WiiChuck chuck = WiiChuck();
+
+
+void setup() {
+ Serial.begin(9600);
+ chuck.begin();
+ //chuck.calibrateJoy();
+}
+
+
+void loop() {
+ delay(10);
+
+ chuck.update();
+
+ int jx = chuck.readJoyX(), jy = chuck.readJoyY();
+ int pitch = chuck.readPitch(), roll = chuck.readRoll();
+
+ Serial.print(jx);
+ Serial.print(",");
+ Serial.print(jy);
+ Serial.print(",");
+
+ Serial.print(pitch);
+ Serial.print(",");
+ Serial.print(roll);
+ Serial.print(",");
+
+ if (chuck.buttonC) {
+ Serial.print("C");
+ } else {
+ Serial.print('-');
+ }
+ Serial.print(",");
+ if (chuck.buttonZ) {
+ Serial.print("Z");
+ } else {
+ Serial.print("-");
+ }
+
+ Serial.print("\n");
+}