Shinichiro Nakamura
/
Drive2ChoroQ
This is a demonstration of two Choro Q Hybrid cars.
Revision 0:d825f8dae2be, committed 2010-11-22
- Comitter:
- shintamainjp
- Date:
- Mon Nov 22 12:23:23 2010 +0000
- Commit message:
- Initial version.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/appconf.cpp Mon Nov 22 12:23:23 2010 +0000 @@ -0,0 +1,87 @@ +#include "appconf.h" +#include <ConfigFile.h> + +LocalFileSystem fs_local("local"); + +/* + * Configuration File Example. + * + * Ch1=A + * Ch2=B + */ + +#define CONFIG_FILENAME "/local/SETUP.CFG" + +#define KEY_CH1 "Ch1" +#define KEY_CH2 "Ch2" +#define VALUE_CHANNEL_A "A" +#define VALUE_CHANNEL_B "B" +#define VALUE_CHANNEL_C "C" +#define VALUE_CHANNEL_D "D" + +/** + * Initialize a configuration. + * + * @param p A pointer to a configuration structure. + */ +void appconf_init(appconf_t *p) { + p->ch1 = ChoroQ::ChA; + p->ch2 = ChoroQ::ChB; +} + +/** + * Get a channel from the key. + * + * @param cf A pointer to a config file object. + * @param p A pointer to a application config. + * @param key The key. + * @param ch A pointer to the channel. + * + * @return Return 0 if it succeed. + */ +static int getChannel(ConfigFile *cf, appconf_t *p, char *key, ChoroQ::Channel *ch) { + char value[64]; + if (!cf->getValue(key, value, sizeof(value))) { + return -1; + } + + if (strcmp(value, VALUE_CHANNEL_A) == 0) { + *ch = ChoroQ::ChA; + return 0; + } else if (strcmp(value, VALUE_CHANNEL_B) == 0) { + *ch = ChoroQ::ChB; + return 0; + } else if (strcmp(value, VALUE_CHANNEL_C) == 0) { + *ch = ChoroQ::ChC; + return 0; + } else if (strcmp(value, VALUE_CHANNEL_D) == 0) { + *ch = ChoroQ::ChD; + return 0; + } else { + return -2; + } +} + +/** + * Read a configuration. + * + * @param p A pointer to a configuration structure. + * + * @return Return 0 if read succeed. + */ +int appconf_read(appconf_t *p) { + ConfigFile cfg; + + if (!cfg.read(CONFIG_FILENAME)) { + return -1; + } + + if (getChannel(&cfg, p, KEY_CH1, &p->ch1) != 0) { + return -2; + } + if (getChannel(&cfg, p, KEY_CH2, &p->ch2) != 0) { + return -3; + } + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/appconf.h Mon Nov 22 12:23:23 2010 +0000 @@ -0,0 +1,27 @@ +#ifndef _APPCONF_H_ +#define _APPCONF_H_ + +#include "ChoroQ.h" + +typedef struct { + ChoroQ::Channel ch1; + ChoroQ::Channel ch2; +} appconf_t; + +/** + * Initialize a configuration. + * + * @param p A pointer to a configuration structure. + */ +void appconf_init(appconf_t *p); + +/** + * Read a configuration. + * + * @param p A pointer to a configuration structure. + * + * @return Return 0 if read succeed. + */ +int appconf_read(appconf_t *p); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extlib/WiiNunchuck/I2CConfig.h Mon Nov 22 12:23:23 2010 +0000 @@ -0,0 +1,48 @@ +/* +* WiiNunchuckReader. A program allowing the output of one or two +* Wii Nunchucks to be read via I2C and decoded for use, using the mbed +* microcontroller and its associated libraries. +* +* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of WiiNunchuckReader. +* +* WiiNunchuckReader is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* WiiNunchuckReader is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with WiiNunchuckReader. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SNATCH59_I2CCONFIG_H +#define SNATCH59_I2CCONFIG_H + +#include <mbed.h> + +class I2CPort_A { +public: + static const PinName SDA; + static const PinName SCL; +}; + + +class I2CPort_B { +public: + static const PinName SDA; + static const PinName SCL; +}; + +const PinName I2CPort_A::SDA = p9; +const PinName I2CPort_A::SCL = p10; + +const PinName I2CPort_B::SDA = p28; +const PinName I2CPort_B::SCL = p27; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extlib/WiiNunchuck/WiiNunchuckDefs.h Mon Nov 22 12:23:23 2010 +0000 @@ -0,0 +1,55 @@ +/* +* WiiNunchuckReader. A program allowing the output of one or two +* Wii Nunchucks to be read via I2C and decoded for use, using the mbed +* microcontroller and its associated libraries. +* +* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of WiiNunchuckReader. +* +* WiiNunchuckReader is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* WiiNunchuckReader is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with WiiNunchuckReader. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SNATCH59_WIINUNCHUCKDEFS_H +#define SNATCH59_WIINUNCHUCKDEFS_H + +// I2C +#define NUNCHUCK_ADDR 0xA4 // I2C library doesn't right shift the address, so provided shifted +#define NUNCHUCK_REGADDR 0x40 // relevant register address +#define NUNCHUCK_READLEN 0x06 // always read this many bytes back + +// received byte position +#define JOY_X 0 +#define JOY_Y 1 +#define ACCEL_X 2 +#define ACCEL_Y 3 +#define ACCEL_Z 4 +#define ADDITIONAL 5 + +// bitmasks for addition info byte +#define MASK_CZ 0x03 +#define MASK_ACCLX1 0x04 +#define MASK_ACCLX2 0x08 +#define MASK_ACCLY1 0x10 +#define MASK_ACCLY2 0x20 +#define MASK_ACCLZ1 0x40 +#define MASK_ACCLZ2 0x80 + +// timing +#define I2C_READ_DELAY 0.01 + +// I2C status +#define I2C_OK 0 // zero on success (ACK), non-zero on fail (NACK) for read or write + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extlib/WiiNunchuck/WiiNunchuckReader.cpp Mon Nov 22 12:23:23 2010 +0000 @@ -0,0 +1,118 @@ +/* +* WiiNunchuckReader. A program allowing the output of one or two +* Wii Nunchucks to be read via I2C and decoded for use, using the mbed +* microcontroller and its associated libraries. +* +* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of WiiNunchuckReader. +* +* WiiNunchuckReader is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* WiiNunchuckReader is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with WiiNunchuckReader. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "WiiNunchuckReader.h" + +// constructor +WiiNunchuckReader::WiiNunchuckReader(PinName sda, PinName scl) : + joyX(0), joyY(0), accelX(0), accelY(0), accelZ(0), + buttonC(0), buttonZ(0), nunchuckInit(false), + nunchuckPort(sda, scl) { +} + +void WiiNunchuckReader::RequestRead() { + // don't expect client to remember to send an init to the nunchuck + // so do it for them here + if (!nunchuckInit) { + nunchuckInit = NunchuckInit(); + } + + if (nunchuckInit) { // don't start reading if init failed + if (NunchuckRead()) { + // only decode successful reads + NunchuckDecode(); + } + } +} + +bool WiiNunchuckReader::NunchuckInit() { + bool success = false; + + const BYTE cmd[] = {NUNCHUCK_REGADDR, 0x00}; + if (I2C_OK == nunchuckPort.write(NUNCHUCK_ADDR, (const char*)cmd, sizeof(cmd))) success = true; + + return success; +} + +bool WiiNunchuckReader::NunchuckRead() { + bool success = false; + + // write the address we want to read from + const BYTE cmd[] = {0x00}; + if (I2C_OK == nunchuckPort.write(NUNCHUCK_ADDR, (const char*)cmd, sizeof(cmd))) { + // the Wii Nunchuck is non-standard I2C + // and can't manage setting the read address and immediately supplying the data + // so wait a bit + wait(I2C_READ_DELAY); + + if (I2C_OK == nunchuckPort.read(NUNCHUCK_ADDR, readBuf, sizeof(readBuf))) success = true; + } + + return success; +} + +void WiiNunchuckReader::NunchuckDecode() { + joyX = (int)readBuf[JOY_X]; + joyY = (int)readBuf[JOY_Y]; + + // the accelerometer axis values are really 10 bit values + // so shift the 8 bit values read from the nunchuck + // 2 bits to the right + accelX = (int)readBuf[ACCEL_X] << 2; + accelY = (int)readBuf[ACCEL_Y] << 2; + accelZ = (int)readBuf[ACCEL_Z] << 2; + + DecodeAdditional(); +} + +void WiiNunchuckReader::DecodeAdditional() { + // the nunchcuk buttons have their own idea of state + int buttonState = readBuf[ADDITIONAL] & MASK_CZ; + switch (buttonState) { + case 3: + buttonZ = 0; + buttonC = 0; + break; + case 2: + buttonZ = 1; + buttonC = 1; + break; + case 1: + buttonZ = 0; + buttonC = 1; + break; + case 0: + buttonZ = 1; + buttonC = 0; + break; + } + + // and the accelerometer axis - for each axis value add bit 1 and bit 0 + // as required + if (readBuf[ADDITIONAL] & MASK_ACCLX1) accelX += 2; + if (readBuf[ADDITIONAL] & MASK_ACCLX2) accelX += 1; + if (readBuf[ADDITIONAL] & MASK_ACCLY1) accelY += 2; + if (readBuf[ADDITIONAL] & MASK_ACCLY2) accelY += 1; + if (readBuf[ADDITIONAL] & MASK_ACCLZ1) accelZ += 2; + if (readBuf[ADDITIONAL] & MASK_ACCLZ2) accelZ += 1; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extlib/WiiNunchuck/WiiNunchuckReader.h Mon Nov 22 12:23:23 2010 +0000 @@ -0,0 +1,95 @@ +/* +* WiiNunchuckReader. A program allowing the output of one or two +* Wii Nunchucks to be read via I2C and decoded for use, using the mbed +* microcontroller and its associated libraries. +* +* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk> +* +* This file is part of WiiNunchuckReader. +* +* WiiNunchuckReader is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* WiiNunchuckReader is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with WiiNunchuckReader. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SNATCH59_WIINUNCHUCKREADER_H +#define SNATCH59_WIINUNCHUCKREADER_H + +#include <mbed.h> +#include "WiiNunchuckDefs.h" + +typedef unsigned char BYTE; + +class WiiNunchuckReader { +public: + // constructors + WiiNunchuckReader(PinName sda, PinName scl); + + // functions + void RequestRead(); + + // accessors + int getJoyX() const { + return joyX; + } + int getJoyY() const { + return joyY; + } + int getAccelX() const { + return accelX; + } + int getAccelY() const { + return accelY; + } + int getAccelZ() const { + return accelZ; + } + int getButtonC() const { + return buttonC; + } + int getButtonZ() const { + return buttonZ; + } + int getBufferSize() const { + return sizeof(readBuf); + } + char* getReadBuf() { + return readBuf; + } + +private: + // nunchuck controls states + int joyX; + int joyY; + int accelX; + int accelY; + int accelZ; + int buttonC; + int buttonZ; + + // nunchuck init state + bool nunchuckInit; + + // nunchuck I2C port + I2C nunchuckPort; + + // read data + char readBuf[NUNCHUCK_READLEN]; + + // functions + bool NunchuckInit(); + bool NunchuckRead(); + void NunchuckDecode(); + void DecodeAdditional(); +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Nov 22 12:23:23 2010 +0000 @@ -0,0 +1,164 @@ +/** + * StarBoard Orange - Example application No.3 (Version 0.0.1) + * Drive a CHORO Q HYBRID with wii nunchuk + * + * See also ... http://mbed.org/users/shintamainjp/notebook/starboard_example3_ja/ + * See also ... http://mbed.org/users/shintamainjp/notebook/starboard_example3_en/ + * + * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems) + * http://shinta.main.jp/ + */ + +/* + * Connection map. + * + * +---+----------------+---------+ + * |Pin|Target |Direction| + * +---+----------------+---------+ + * |p21|IR transmitter |OUT | + * +---+----------------+---------+ + */ + +/* + * Include files. + */ + +#include <mbed.h> +#include <algorithm> +#include <ChoroQ.h> +#include <I2CConfig.h> +#include <WiiNunchuckReader.h> +#include "appconf.h" + +/* + * Objects. + */ + +WiiNunchuckReader wn1(I2CPort_A::SDA, I2CPort_A::SCL); +WiiNunchuckReader wn2(I2CPort_B::SDA, I2CPort_B::SCL); +ChoroQ cq(p21); +BusOut led(LED4, LED3, LED2, LED1); + +/** + * Display a splash screen. + */ +void splash(void) { + // Do nothing. +} + +/** + * Get an action from a coordinate. + * + * @param x X axis. + * @param y Y axis. + * @param dash State of dash. + * + * @return An action. + */ +ChoroQ::Action getAction(const int x, const int y, bool dash) { + static const int MAX_X = 200; + static const int MIN_X = 20; + static const int MAX_Y = 200; + static const int MIN_Y = 20; + int px = ((x - MIN_X) * 100) / (MAX_X - MIN_X); + int py = ((y - MIN_Y) * 100) / (MAX_Y - MIN_Y); + px = std::max(0, std::min(100, px)) - 50; // Range of a value is -50 to +50 + py = std::max(0, std::min(100, py)) - 50; // Range of a value is -50 to +50 + + if ((std::abs(px) <= 10) && (std::abs(py) <= 10)) { + return ChoroQ::Stop; + } + + if ((x == 0) && (y == 0)) { + return ChoroQ::Stop; + } + + if (std::abs(px) < 10) { + if (py < 0) { + if (dash) { + return ChoroQ::DownDash; + } else { + return ChoroQ::Down; + } + } else { + if (dash) { + return ChoroQ::UpDash; + } else { + return ChoroQ::Up; + } + } + } + if (std::abs(py) < 10) { + if (px < -20) { + return ChoroQ::Left; + } + if (20 < px) { + return ChoroQ::Right; + } + } + if ((10 < px) && (10 < py)) { + if (dash) { + return ChoroQ::UpRightDash; + } else { + return ChoroQ::UpRight; + } + } + if ((px < -10) && (10 < py)) { + if (dash) { + return ChoroQ::UpLeftDash; + } else { + return ChoroQ::UpLeft; + } + } + if ((px < -10) && (py < -10)) { + if (dash) { + return ChoroQ::DownLeftDash; + } else { + return ChoroQ::DownLeft; + } + } + if ((10 < px) && (py < -10)) { + if (dash) { + return ChoroQ::DownRightDash; + } else { + return ChoroQ::DownRight; + } + } + return ChoroQ::Stop; +} + +/** + * Entry point. + */ +int main() { + /* + * Splash. + */ + splash(); + + /* + * Setup a configuration. + */ + appconf_t conf; + appconf_init(&conf); + if (appconf_read(&conf) != 0) { + error("Please check the configuration."); + } + + /* + * Application loop. + */ + while (true) { + led = led + 1; + wn1.RequestRead(); + ChoroQ::Action ac1 = getAction(wn1.getJoyX(), wn1.getJoyY(), (wn1.getButtonZ() == 1) ? true : false); + cq.execute(conf.ch1, ac1, false); + wait_ms(25); + + led = led + 1; + wn2.RequestRead(); + ChoroQ::Action ac2 = getAction(wn2.getJoyX(), wn2.getJoyY(), (wn2.getButtonZ() == 1) ? true : false); + cq.execute(conf.ch2, ac2, false); + wait_ms(25); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Mon Nov 22 12:23:23 2010 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/e2ac27c8e93e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mylib/ChoroQ.lib Mon Nov 22 12:23:23 2010 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/shintamainjp/code/ChoroQ/#97921a2adf78
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mylib/ConfigFile.lib Mon Nov 22 12:23:23 2010 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/shintamainjp/code/ConfigFile/#f6ceafabe9f8