Braccio comandato
di Daniele Giangravè
ultimo aggiornamento 17 maggio 2015


JLCPCB - 10 PCB per $ 2 (100 * 100 mm, 2-layer)
Il più grande produttore di PCB in Cina, oltre 600.000 clienti e oltre 10.000 ordini online al giorno
Produzione veloce in sole 24 ore e preventivo online gratuito: https://jlcpcb.com/quote


Il braccio robot proposto da Daniele Giangravè è costruito con pezzi di legno rivestiti di carta colorata, ed è dotato da 3 servomotori tipo HS-485HS sono prodotti dalla HITEC.
Questo braccio robotico ideato per avere un mezzo che possa muovere oggetti di vario tipo come per esempio metri ottici per effettuare misure o una telecamera che riprenda nella direzione desiderata senza che ci sia un addetto che fisicamente la sposti.
Il tutto è mosso dal cellulare attraverso un applicazione per smartphone android creata con java per android che sfrutta la tecnologia bluetooth e touchscreen del cellulare rispettivamente per assegnare le coordinate ai motori trascinando il dito sullo schermo e per configurare il dispositivo con la scheda che gestisce il robot col vantaggio dunque di non avere l’intralcio dei fili da collegare.
La scheda utilizzata è la IOIO OTG per Android, che è in grado di interfacciarsi con lo smarthphone attraverso l’applicazione “Robot” che all’interno contiene comandi per muovere ogni singolo asse di uno step aumentando così la precisione di movimento nel qual caso si voglia sostituire il puntatore laser con un metro ultrasuoni permettendo di effettuare misure molto precise.
La scheda accenderà il led blu quando entrerà in collegamento con il cellulare.

OurPCB, your most reliable PCB and PCBA supplier.

 

Lo IOIO-OTG (pronunciato "yo-yo-O-T-G") è una scheda di sviluppo progettata da SeeedStudio e Sparkfun Electronics per aggiungere un hardware con avanzate capacità I/O alle applicazione Android o PC

Possiede un microcontrollore PIC che si comporta come un ponte tra le app sul dispositivo PC o android alle periferiche di basso livello come GPIO, PWM, ADC, I2C, SPI e UART.
Una libreria a livello app aiuta a scrivere il codice di controllo per quelle periferiche di basso livello allo stesso modo in cui scrivi app per Java!
Ci sono diversi modi di connettere la IOIO alle app Java.
Se la app sta girando su un dispositivo Android, la IOIO-OTG si comporterà come un host USB e fornirà la corrente di carica al dispositivo (ovvero la IOIO-OTG avrà bisogno di una fonte di energia). Se la tua app sta girando su Windows, Linux o OSX la IOIO-OTG entrerà in device mode e si presenterà come una porta seriale virtuale.
Quando si trova in device mode, la IOIO-OTG può essere alimentata dall'host!
Connettendo un dongle USB bluetooth porterà la IOIO-OTG a mostrarsi come una connessione seriale bluetooth.
Un interruttore sulla scheda può essere usato per forzare la IOIO-OTG nella modalità host, ma la maggior parte delle volte la scheda può essere lasciata in modalità automatica e determinerà da sola il suo ruolo nella connessione.
La IOIO-OTG è caricata con bootloader V4.00 e application firmware V3.30.
Nuovi application firmware vengono rilasciati frequentemente ed è possibile fare un upgrade senza bisogno di programmare usando applicazioni IOIODue.
La scheda include un connettore JST per collegare batterie LiPo e ci sono diversi connettori pin per il voltaggio e ground.
Un trimmer sulla scheda permette di regolare la corrente di carica usata quando la IOIO.OTG sta fungendo da host.
Un cavo USB-A a micro-A OTG è incluso vi permetterà di connettei il dispositivo android alla porta micro-USB sulla scheda usando il cavo che arriva con il dispositivo android


 

Documenti:

 

I servocomandi HS-485HS sono prodotti dalla HITEC e sono dei servocomando standard, con ingranaggi in carbonite, cuscinetto a sfere metallico, molto potente, preciso ed economico

Segnale di controllo  Impulso positivo 1,5ms per posizione centrale
Ampiezza segnale  3-5 Volt Peak to Peak Onda quadra
Tensione operativa  4.8-6.0V
Temperatura operativa  Range -20 to +60°
Velocità  4.8V0 -22sec/60° senza carico
Torsione  4.8V - 4.8kgcm
Angolo operativo  60°
360 Modificabile  Yes
Direzione  Oraria con segnale da 1,5 a 1,9msec
Corrente assorbita  4.8V - 8mA fermo, 150mA in rotazione senza carico
Zona morta  8usec
Tipo motore  3 Poli in ferrite brushed
Guida potenziometro  Pilotaggio indiretto
Cuscinetti  1 sommità alberino
Ingranaggi  Karbonite
Lunghezza cavo  30cm
Dimensioni  40x28x19,8mm
Peso  45g

Listato dell'applicazine

 

import android.bluetooth.BluetoothAdapter;

import android.content.Intent;

import android.graphics.Point;

import android.hardware.Sensor;

import android.hardware.SensorEvent;

import android.hardware.SensorEventListener;

import android.hardware.SensorManager;

import android.os.Bundle;

import ioio.lib.api.DigitalOutput;

import ioio.lib.api.DigitalOutput.Spec.Mode;

import ioio.lib.api.PwmOutput;

import ioio.lib.api.exception.ConnectionLostException;

import ioio.lib.api.exception.IncompatibilityException;

import ioio.lib.util.AbstractIOIOActivity;

import android.view.Display;

import android.view.Menu;

import android.view.MenuInflater;

import android.view.MenuItem;

import android.view.MotionEvent;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.ImageView;

import android.widget.SeekBar;

import android.widget.SeekBar.OnSeekBarChangeListener;

import android.widget.TextView;

import android.widget.Toast;

 

public class MainActivity extends AbstractIOIOActivity implements

             SensorEventListener {

       private static final int info = Menu.FIRST;

       BluetoothAdapter blue;

       Intent accendi;

        int limZ = 500;

       Button bt0;

       Button btX;

       Button btY;

       Button btZ;

        int width;

       int height;

       Button bt_laser;

 

       ImageView img2;

       SeekBar sk1;

 

       private SensorManager mSensorManager;

       float volt = 0;

       int x, y = 0;

       int posY = 1500, posX, posZ = 1000;

 

       TextView tx6;

       boolean acceso = false;

       boolean laser_stat = false;

       boolean connesso = false;

       boolean mess_comparso = false;

 

       int xyz = 0;

 

       @Override

       public void onCreate(Bundle savedInstanceState) {

             super.onCreate(savedInstanceState);

             setContentView(R.layout.fragment_main);

 

             mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

             mSensorManager.registerListener(this,

                           mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),

                           SensorManager.SENSOR_DELAY_UI);

 

       tx6 = (TextView) findViewById(R.id.textView6);

        

 

             bt0 = (Button) findViewById(R.id.bt_0);

             btX = (Button) findViewById(R.id.bt_X);

             btY = (Button) findViewById(R.id.bt_Y);

             btZ = (Button) findViewById(R.id.bt_Z);

             sk1 = (SeekBar) findViewById(R.id.seekBar1);

             bt_laser = (Button) findViewById(R.id.bt_laser);

             img2 = (ImageView) findViewById(R.id.imageView2);

 

             Display display = getWindowManager().getDefaultDisplay();

             Point size = new Point();

             display.getSize(size);

             width = size.x;

             height = size.y;

 

             blue = BluetoothAdapter.getDefaultAdapter();

 

             if (!blue.isEnabled()) {

                    accendi = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

                    startActivity(accendi);

 

             }

 

             if (blue.isEnabled())

                    Toast.makeText(MainActivity.this, "Bluetooth acceso",

                                  Toast.LENGTH_LONG).show();

 

             sk1.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

 

                    int progress = 0;

 

                    @Override

                    public void onProgressChanged(SeekBar seekBar, int progresValue,

                                  boolean fromUser) {

                           if (xyz == 0) {

                                  posX = progresValue;

 

                           }

                           if (xyz == 1) {

 

                                  if (progresValue <= 1350) {

 

                                        if (posZ <= limZ + 100)

                                               posZ += 30;

                                        else

                                               posY = progresValue;

                                  } else

                                        posY = progresValue;

 

                                  if (posY >= 2000)

                                        posY = 2000;

 

                           }

                           if (xyz == 2) {

 

                                  if (posY <= 1150) {

                                        if (progresValue >= limZ)

                                               posZ = progresValue;

                                  } else

                                        posZ = progresValue;

 

                           }

 

                    }

 

                    public void onStartTrackingTouch(SeekBar seekBar) {

                    }

 

                    @Override

                    public void onStopTrackingTouch(SeekBar seekBar) {

 

                    }

 

             });

             btX.setOnClickListener(new OnClickListener() {

 

                    public void onClick(View v) {

 

                           xyz = 0;

                           bt0.setBackgroundResource(R.drawable.blu2_settings);

                           tx6.setText("X");

                    }

             });

 

             btY.setOnClickListener(new OnClickListener() {

 

                    public void onClick(View v) {

 

                           xyz = 1;

                           bt0.setBackgroundResource(R.drawable.verde2_settings);

 

                           tx6.setText("Y");

                    }

             });

 

             btZ.setOnClickListener(new OnClickListener() {

 

                    public void onClick(View v) {

                           xyz = 2;

                           bt0.setBackgroundResource(R.drawable.giallo_normal);

 

                           xyz = 2;

                           tx6.setText("Z");

 

                    }

 

             });

 

             bt0.setOnClickListener(new OnClickListener() {

 

                    public void onClick(View v) {

 

                           if (xyz == 0)

                                  posX = 10;

                           if (xyz == 1)

                                  posY = 10;

                           if (xyz == 2)

                                  posZ = 10;

 

                    }

             });

 

             bt_laser.setOnClickListener(new OnClickListener() {

 

                    public void onClick(View v) {

 

                           if (laser_stat == false)

                                  laser_stat = true;

                           else

                                  laser_stat = false;

                           if (laser_stat == true)

                                  bt_laser.setBackgroundResource(R.drawable.acceso_settings);

                           else

                                  bt_laser.setBackgroundResource(R.drawable.arancione_settings);

 

                    }

             });

       }

 

       public void onSensorChanged(SensorEvent event) {

 

             if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

 

                    x = (int) event.values[1];

                    y = (int) event.values[2];

 

                    if (posY <= 1250)

                           if (posY > 900)

                                  if (posZ <= limZ)

                                        while (posZ < limZ + 100)

                                               posZ += 30;

 

                    if (posY <= 1470)

                           if (posY >= 1150)

                                  if (posZ <= 300)

                                        posZ += 50;

 

                    if (connesso == true) {

                           img2.setImageResource(R.drawable.verde);

                           if (mess_comparso == false) {

                                  Toast.makeText(MainActivity.this, "Scheda connessa",

                                               Toast.LENGTH_LONG).show();

                                  mess_comparso = true;

                           }

                    } else

                           img2.setImageResource(R.drawable.rosso);

             }

 

       }

 

       public boolean onTouchEvent(MotionEvent event) {

 

             y = (int) event.getY();

             x = (int) event.getX();

 

             if ((height >= 880) && (height <= 960)) {

                    posX = (int) (x * (2100 / width) * 640 / 540);

                    if (y < 250)

                           y = 0;

                    else {

 

                           posY = (int) (((y - 250) * (2000 / (height - 250))) * 960 / height);

                    }

 

                    if (posY < 0)

                           posY = 0;

             } else {

 

                    posX = (int) (x * (2100 / width));

                    if (y < 150)

                           y = 0;

                    else {

                           posY = (int) (((y - 150) * (2000 / (height - 150))) * 480 / height);

                    }

 

                    if (posY < 0)

                           posY = 0;

             }

 

             if (posX >= 2000)

                    posX = 2000;

             if (posY >= 2000)

                    posY = 2000;

 

             return true;

 

       }

 

       class IOIOThread extends AbstractIOIOActivity.IOIOThread {

 

             private PwmOutput servoX;

             private PwmOutput servoY;

             private PwmOutput servoZ;

             private PwmOutput led;

             private DigitalOutput laser;

 

             public void setup() throws ConnectionLostException {

                    try {

                           ioio_.waitForConnect();

                    } catch (IncompatibilityException e1) {

                           // TODO Auto-generated catch block

                           e1.printStackTrace();

                    }

                    try {

 

                           acceso = true;

                           servoX = ioio_.openPwmOutput(new DigitalOutput.Spec(35,

                                        Mode.OPEN_DRAIN), 50);

                           servoY = ioio_.openPwmOutput(new DigitalOutput.Spec(40,

                                        Mode.OPEN_DRAIN), 50);

                           servoZ = ioio_.openPwmOutput(new DigitalOutput.Spec(45,

                                        Mode.OPEN_DRAIN), 50);

 

                           led = ioio_.openPwmOutput(39, 1000);

                           laser = ioio_.openDigitalOutput(43);

 

                    } catch (ConnectionLostException e) {

 

                           throw e;

                    }

 

             }

 

             public void loop() throws ConnectionLostException {

                    try {

                           connesso = true;

                           servoX.setPulseWidth(posX);

                           if (posY > 550)

                                  servoY.setPulseWidth(posY);

                           servoZ.setPulseWidth(2500 - posZ);

 

                           led.setPulseWidth(800);

                           laser.write(laser_stat);

                           sleep(10);

                    } catch (InterruptedException e) {

                           ioio_.disconnect();

                           img2.setImageResource(R.drawable.rosso);

                           acceso = false;

                    } catch (ConnectionLostException e) {

                           throw e;

                    }

 

             }

       }

 

       @Override

       protected AbstractIOIOActivity.IOIOThread createIOIOThread() {

             return new IOIOThread();

       }

 

       @Override

       public void onAccuracyChanged(Sensor sensor, int accuracy) {

             // TODO Auto-generated method stub

       }

 

       @Override

       public boolean onCreateOptionsMenu(Menu menu) {

             super.onCreateOptionsMenu(menu);

             menu.add(Menu.NONE, info, Menu.NONE, R.string.informazioni);

 

             return true;

 

       }

 

       @Override

       public boolean onOptionsItemSelected(MenuItem item) {

 

             int id = item.getItemId();

             if (id == info) {

                    Intent in = new Intent(MainActivity.this, Informazioni_class.class);

                    startActivity(in);

             }

             return super.onOptionsItemSelected(item);

       }

}

 

Elenco revisioni

17/05/2015

Emissione preliminare