element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Members
    Members
    • Benefits of Membership
    • Achievement Levels
    • Members Area
    • Personal Blogs
    • Feedback and Support
    • What's New on element14
  • Learn
    Learn
    • Learning Center
    • eBooks
    • STEM Academy
    • Webinars, Training and Events
    • More
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • More
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • More
  • Products
    Products
    • Arduino
    • Dev Tools
    • Manufacturers
    • Raspberry Pi
    • RoadTests & Reviews
    • Avnet Boards Community
    • More
  • Store
    Store
    • Visit Your Store
    • Choose Another Store
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
Off the Shelf
  • Challenges & Projects
  • Project14
  • Off the Shelf
  • More
  • Cancel
Off the Shelf
Blog Arduino Nano as Raspberry Pi IO expander w/ I2C - VOILA ! - the copter joystick controls I2C to Raspberry Pi WORKS !
  • Blog
  • Forum
  • Documents
  • Events
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Off the Shelf requires membership for participation - click to join
Blog Post Actions
  • Subscribe by email
  • More
  • Cancel
  • Share
  • Subscribe by email
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
Author: robogary
Date Created: 29 Sep 2021 11:33 PM
Views: 370
Likes: 0
Comments: 2
  • offtheshelfch
Related
Recommended

Arduino Nano as Raspberry Pi IO expander w/ I2C - VOILA ! - the copter joystick controls I2C to Raspberry Pi WORKS !

robogary
robogary
29 Sep 2021

Off the shelf and open the storage container.

This project is 4-5 years old, it has had many spec changes over the years.  It features a Raspberry Pi, a GPIO expander to solderless breadboards, I2C servo hat, and an Arduino Nano wired on the I2C bus, with other I2C sensors. This competition gave the project hope, and eventually life !

 

Here it the completed project in action !   https://youtu.be/eMoC8VlGKAU

 

Original Goal:

A DC brushless rotor motor’s speed is to be controlled by a Raspberry Pi using a I2C servo hat, receiving throttle data from the Arduino I2C.

The project goal is to send the joystick position from the Arduino to the Raspberry Pi using I2C for main rotor speed control.

A 3D helicopter printed helicopter has a DC brushless outboard motor mounted on it as main rotor (with a model airplane prop on it mounted upside down.)

 

The tail rotor is a WS2812 neopixel ring was wired to the Arduino Nano, also using the joystick positions for color and speed of LED flashing.

The tail rotor neopixel ring will change cycling speeds with the joystick position FWD-Back.

The tail rotor neopixel ring will change colors  with the joystick position, center, left , and right.

 

Workscope Creep - the overly demanding and ambitious project leader seizes the opportunity to add features to enhance the safety and wow factor of the original design.

  1. using the integrated joystick switch, create a rotor motor enable signal which resides in the Arduino Nano.

The enable signal will toggle by pressing down on the joystick.

When rotor motor is enabled, LED13 on the Arduino will be lit as visual feedback of a possible danger condition.

When the rotor motor is disabled, LED13 will be out.

The rotor motor enable bit is sent over I2C to cause the rotor motor speed reference to be set to zero when LOW.

When the rotor motor enable bit is HIGH, the rotor motor servo speed reference will follow the FwdBack joystick position. Full Back = top speed ( 90 degrees reference = 1.5 ms on the 20ms duty cycle) stick full back slows it to zero speed.

  1. YAW CONTROL The 3D printed copter will be mounted on a 2 axis servo bracket. The bottom servo position will be controlled by the left/right joystick so full left points the copter left, full right points the copter right. The servo position reference will have reference rate clamps so reduce mechanical stress on the mechanicals.
  2. PITCH (TILT) CONTROL – on the 2 axis servo bracket, the upper servo position will be controlled by the Fwd/Back joystick. The angle and rate will be limited to reduce mechanical stresses.

 

Here it the completed project in action !   https://youtu.be/eMoC8VlGKAU

In the body of this submission is Arduino code, Raspberry Pi Python code, and the wiring schematics !

 

 

 

 

 

 

slave_sender_w_NeoPixel_JoystickWORKS_.ino

// Wire Slave Sender

// by Nicholas Zambetti <http://www.zambetti.com>

 

// Demonstrates use of the Wire library

// Sends data as an I2C/TWI slave device

// Refer to the "Wire Master Reader" example for use with this

 

// Created 29 March 2006

 

// This example code is in the public domain.

 

 

#include <Wire.h>

int number = 0;

int state = 0;

 

 

#include <Adafruit_NeoPixel.h>

#define PIXEL_PIN 11    // Digital IO pin connected to the NeoPixels.

#define PIXEL_COUNT 16

 

// Parameter 1 = number of pixels in strip,  neopixel stick has 8

// Parameter 2 = pin number (most are valid)

// Parameter 3 = pixel type flags, add together as needed:

//   NEO_RGB     Pixels are wired for RGB bitstream

//   NEO_GRB     Pixels are wired for GRB bitstream, correct for neopixel stick

// NEO_KHZ400  400 KHz bitstream (e.g. FLORA pixels)

// NEO_KHZ800  800 KHz bitstream (e.g. High Density LED strip), correct for neopixel stick

Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);

 

// joystick left A4=0v joystick right A4 = 4.7v  nuetral position = 2.5V (512 counts)

// joystick back A5=0V joystick full fwd A5=4.7v  nuetral position = 2.5V  (512 counts)

// 10-bit analog to digital converter. input voltages between 0 and 5 volts correspond to integer values between 0 and 1023.

// lower byte of an analog value reads 0-255, upper byte 256-1023

 

int Joystick_FwdRev=0;

int Joystick_LeftRight=0;

int Red =0;

int Green=0;

byte IOBytes[5]; // setup a matrix for IO Bytes of data

int LEDcycleTime; // for WS2812 update time infuenced by throttle joystick

int JoystickSwitch; //

int EnableServos= LOW;

int EnableServosLastScan= LOW;

byte ArduinoDigitalIns=0; // a generic byte to map inputs to the Raspberry Pi

 

void setup() {

  strip.begin();

  delay (2000); // give time for the LEDs to initialize

  strip.show(); // Initialize all pixels to 'off'

 

  byte IOBytes[5];  // setup a matrix for IO Bytes of data

  int Joystick_FwdRev=0;

  int Joystick_LeftRight=0;

  int EnableServos= LOW;

 

 

  //SW (KEY or SEL) – This is the digital output from the pushbutton, normally open, will connect to GND when the button is pushed.

  pinMode(12, INPUT_PULLUP);      // sets the digital pin 12 as an input for the joystick switch

 

 

Wire.begin(8);                // join i2c bus with address #8

// Wire.onRequest(requestEvent); // register event

// Serial.begin(9600); //  setup serial monitor

Wire.onReceive(receiveData);

Wire.onRequest(sendData);

// Serial.println("Ready!");

 

}

 

void loop() {

 

  //this code block determines color of rotor.

  //Red when turning LEFT , Green when turning right, yellow at stick nuetral (255, 255, 0)

 

Joystick_LeftRight = analogRead(A2);

  Joystick_FwdRev = analogRead(A1);

// Serial.println(Joystick_LeftRight);

 

  if (Joystick_LeftRight >= 520 )

      {Red = 0;

       Green = 30;

       }

  if ((Joystick_LeftRight < 520 )&& (Joystick_LeftRight >= 480 ))

      {

        Red = 30;

        Green = 30;

       }

if (Joystick_LeftRight < 480)

      { Red = 30;

        Green = 0;

       }

 

  for (int i = 0; i<16; i++)

    {

Joystick_FwdRev = analogRead(A1); // read throttle joystick position

      LEDcycleTime = 50-(Joystick_FwdRev/32);  // throttle full back delay ~ 60ms, full fwd delay time is ~16ms , nuetral position ~ 34ms

   

strip.setPixelColor(i,Red,Green,0); // this is an LED sequence starting from LED #1

      int j=(i+8);

      if ((i+8)>16)

        {j=(i-8);}

strip.setPixelColor((j),Red,Green,0); // // this is an LED sequence starting from LED #8

      strip.show();

      delay (LEDcycleTime);

strip.setPixelColor(i,0,0,0); //

strip.setPixelColor((j),0,0,0); // this is an LED sequence starting from LED #8

      strip.show();

      delay (3);

    // each pass takes

    }

 

//  delay(100);

////////////////////////// ENABLE SERVOs - send this bit to the Raspberry Pi & light the Arduino LED13 /////////////////////////////////////////////////

JoystickSwitch = digitalRead(12);   // read the input pin

 

  if ((JoystickSwitch == LOW)&& (EnableServos==LOW)&&(EnableServosLastScan==LOW))  //LastScan value to eliminate race condition

    {

EnableServos=HIGH;  // this toggles enable high

      delay (20);

    }

 

if ((JoystickSwitch == LOW)&& (EnableServos==HIGH)&&(EnableServosLastScan==HIGH)) // joystick input has a pullup , reads LOW when pushed

      {

EnableServos=LOW;  //this is used to toggle off enable

      delay (20);

    }

 

 

if (EnableServos==LOW)

  {

digitalWrite(13, LOW);

    bitWrite(ArduinoDigitalIns, 0, 0);

  }

else {

   digitalWrite(13, HIGH);

bitWrite(ArduinoDigitalIns, 0, 1);

      }

 

// Serial.print ("JoystickSwitch ="); //confirmed 5V = 1023 counts

//  Serial.println (JoystickSwitch);

//  Serial.print ("EnableServos ="); //confirmed 5V = 1023 counts

//  Serial.println (EnableServos);

//  Serial.print ("ArduinoDigitalIns="); //confirmed 5V = 1023 counts

//  Serial.println (ArduinoDigitalIns);

 

EnableServosLastScan = EnableServos; // to eliminate race condition in logic

 

 

// for bebugging fill up the byte matrix of 5 with data, for now only put in the analogs

//  IOBytes[0] = lowByte(Joystick_LeftRight);

//  IOBytes[1] = highByte(Joystick_LeftRight);

//  IOBytes[2] =  lowByte(Joystick_FwdRev);

//  IOBytes[3] =  highByte(Joystick_FwdRev);

//  IOBytes[4] = lowByte(16); // use for debugging, later for reading DIs

//  Serial.print ("Joystick_LeftRight ="); //confirmed 5V = 1023 counts

//  Serial.println (Joystick_LeftRight);

// Serial.print("Joystick_LeftRight low byte =");

//  Serial.println (IOBytes[0]);  // low byte value max = 255

// Serial.print("Joystick_LeftRight hi byte =");  // hi byte max value = 3

// Serial.println (IOBytes[1]);

//  Serial.println (" ");

//  Serial.println (" ");

// Serial.print("Joystick_FwdRev =");

//  Serial.println (Joystick_FwdRev);

// Serial.print("Joystick_FwdRev lo byte =");

//  Serial.println (IOBytes[2]);

// Serial.print("Joystick_FwdRev hi byte =");

//  Serial.println (IOBytes[3]);

// Serial.print("constant lo byte =");

//  Serial.println (IOBytes[4]);

//  Serial.println (" ");

}

 

 

// function that executes whenever data is requested by master

// this function is registered as an event, see setup()

// send 5 bytes of data, 2 bytes from A1, 2 bytes from A2, 1 byte as a packed byte of bits from digital inputs

 

//void requestEvent() /

//{

// for (int i=0;i<6;i++)

//  {

// Wire.beginTransmission(9); // transmit to device #9

// Wire.write(IOBytes[i]);

// Wire.send(IOBytes[i]); // sends x

// Wire.endTransmission(); // stop transmitting

//  }

  // as expected by master

// }

 

// callback for received data

void receiveData(int byteCount)

  {

while(Wire.available())

    {

      number = Wire.read();

// Serial.print("data received: ");

// Serial.println(number);

     }

   }

 

// callback for sending data

//Wire.write(data, length)

// Parameters value: a value to send as a single byte

// data: an array of data to send as bytes

// length: the number of bytes to transmit

 

void sendData()

  {

  Joystick_LeftRight = analogRead(A2);

  Joystick_FwdRev = analogRead(A1);

 

  IOBytes[0] = lowByte(Joystick_LeftRight);

  IOBytes[1] = highByte(Joystick_LeftRight);

  IOBytes[2] = lowByte(Joystick_FwdRev);

  IOBytes[3] = highByte(Joystick_FwdRev);

  IOBytes[4] = lowByte (ArduinoDigitalIns); //lowByte(16); // use for debugging, later for reading DIs

Wire.write(IOBytes,5); // dont need the [] brackets on the matrix

}

 

 

 

 

# this filename CopterJoystickI2C_FINAL.py

# it is derived from CopterReadJoystickI2CMatrix.py and AdafruitServoTest2.py

# this program WORKS !!

# to work properly, the Arduino needs to be loaded with slave_sender_w_NeoPixel_JoystickWORKS_.ino

 

#DEBUG CODE is denoted with # to comment it out

 

 

#!!  SETUP FOR I2C !!

import smbus

import time

# for RPI version 1, use "bus = smbus.SMBus(0)"

bus = smbus.SMBus(1)

#!! This is the address we setup in the Arduino Program

address = 0x08

 

#!! SETUP FOR 16 ch servo hat

from adafruit_servokit import ServoKit

kit = ServoKit(channels=16)

  1. kit.servo[0].angle=90 # yaw servo
  2. kit.servo[1].angle=90 # pitch- tilt servo
  3. kit.servo[4].angle=0 ## note prop motor only runs 0-90 for 0 spd to top speed
  4. time.sleep(1)  # leave some time for setup

 

#!! application parameters

YawOffset =0 # in degrees

PitchTiltOffset=0 # in degrees

PitchTiltAngleNoseDownLimit=120 # from 90 degrees = horizontal

PitchTiltAngleNoseUpLimit=50 # from 90 degrees = horizontal

 

while True:

    time.sleep(.1) # time is for slowing down the updates if debugging

    JoystickData = bus.read_i2c_block_data(0x08, 0x00, 5)

#    print (" JoystickData=", JoystickData)

LeftRightJoystick=(JoystickData[0]+(JoystickData[1]*256))

#    print (" LeftRightJoystick =", LeftRightJoystick)

FwdBackJoystick=(JoystickData[2]+(JoystickData[3]*256))

#    print (" FwdBackJoystick =", FwdBackJoystick)

    EnableServos = JoystickData[4]

#    print (" EnableServos =", EnableServos)

 

#!! leftRight joystick values are full left = 0, full right = 1023

#!! FwdBack joystick values are full back = 0, full fwd = 1023

#!! the servos require a reference in degrees

 

#!! the Yaw servo needs 180 to turn left, and 0 is full right,opposite of joystick

#!! the inverted value for Yaw so left joystick makes it turn left is called YawDereesInv

YawDegrees=(((LeftRightJoystick)*180)/1023)+YawOffset # right is zero, left is 180

    YawDegreesInv= (180-YawDegrees)

#!! Ensure YawDegreesInv stays within range

    if (YawDegreesInv>179):

YawDegreesInv=179

    if (YawDegreesInv<1):

YawDegreesInv=1

#    print (" YawDegrees=", YawDegrees)

#    print (" YawDegrees=Inv", YawDegreesInv)

 

 

#!! pitchTilt servo calcs

PitchTiltDegrees=(((FwdBackJoystick)*180)/1023)+PitchTiltOffset

#    print ("PitchTiltDegrees", PitchTiltDegrees)

    if (PitchTiltDegrees>PitchTiltAngleNoseDownLimit):

PitchTiltDegrees=PitchTiltAngleNoseDownLimit

    if (PitchTiltDegrees<PitchTiltAngleNoseUpLimit):

PitchTiltDegrees=PitchTiltAngleNoseUpLimit

 

 

#!! rotor speed calcs

RotorSpeed=(((FwdBackJoystick)*90)/1023) # rotor speed max value is 90

#!! Ensure rotor speed stays in range

    if (RotorSpeed>90):

RotorSpeed=90

    if (RotorSpeed<1):

RotorSpeed=1

 

    if (EnableServos == 0):

RotorSpeed=0

#    print ("RotorSpeed =", RotorSpeed)

    kit.servo[0].angle=YawDegreesInv  #

kit.servo[1].angle=PitchTiltDegrees

kit.servo[4].angle=RotorSpeed  # where 90 degrees is top speed

 

 

 

Part 1 – Original workscope and photos https://www.element14.com/community/community/project14/offtheshelf/blog/2021/09/20/arduino-nano-as-raspberry-pi-io-i2c-expander-part-1-aka-copter-rotor-control-via-i2c-joystick

Part 2 – wiring, hardware, and reading drop numbers on I2C  https://www.element14.com/community/community/project14/offtheshelf/blog/2021/09/20/arduino-nano-as-raspberry-pi-io-i2c-expander-part-2-the-i2c-bus-copter-rotor-control-via-i2c-joystick-

Progress videos: The neopixel tail rotor  controlled by an Arduino Nano from analog joystick inputs.

https://youtu.be/QVE3VqoM3l0

 

You don't have permission to edit metadata of this video.
Edit media
x
Upload Preview

 

The main rotor controlled the Raspberry Pi using Python and I2C servo hat.

https://youtu.be/l5YQBAQblRU

 

You don't have permission to edit metadata of this video.
Edit media
x
Upload Preview

 

Part 3 –  I2C talking Arduino to Raspberry Pi, single data byte.  https://www.element14.com/community/community/project14/offtheshelf/blog/2021/09/22/arduino-nano-as-raspberry-pi-io-i2c-expander-part-3-python-voodoo-the-i2c-bus-byte-me

 

Part 4 – I2C sharing 5 bytes from the Arduino Nano to the Raspberry Pi https://www.element14.com/community/community/project14/offtheshelf/blog/2021/09/28/arduino-nano-as-raspberry-pi-io-i2c-expander-part-4-humbling-persistence-scope-creep-python-voodoo-and-over-the-hump

Anonymous
Parents
  • robogary
    robogary 7 months ago

    its alive !!!!!!!!!!

    • Cancel
    • Up 0 Down
    • Reply
    • More
    • Cancel
Comment
  • robogary
    robogary 7 months ago

    its alive !!!!!!!!!!

    • Cancel
    • Up 0 Down
    • Reply
    • More
    • Cancel
Children
No Data
Element14

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2022 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • Facebook
  • Twitter
  • linkedin
  • YouTube