Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 2 | ||||
| × | 1 |
I've been exploring the Arduino and makers multiverse for months. But I've been building with Lego for decades. :) I saw a little toy on a chinese website, an arachnid moving with a simple but clever system of gears and a motor. I bought it and immediately after our first test, my daughter noticed how it would be cool if we could radio command it. I tought it would be even cooler with Legos!
So we got my old sets and we started assembling pieces and gears to build a first proof of concept. It was already awesome. Then I ordered the missing blocks on BrickLinks and a week later we assembled it according to our own blueprints. Then I added the two motors, the Arduino setup and I took a night to code a little controlling app for my smartphone.
Hiro was fun and quite easy to do, and even more to watch running across the house. Nice silly toy.
[EDIT : If you wanna do it, you'll have to glue most of the bricks because Spideruino is not moving softly. That's quite the opposite, it's brutal, and without glue it felt apart in 3 meters of walking. :) ]
Inner gears.
//ARDUINO Hiro NANO
//RXD to TXO (white)
//TXD to RXO (black) BT adapter
// motor one
int enA = 11; //gris
int in1 = 10; // bleu
int in2 = 9; //vert
// motor two
int enB = 3; // violet
int in3 = 6; // jaune
int in4 = 5; // orange
char command;
String btdata;
int power;
int dir;
// Variables for the duration and the distance
long duration;
int distance;
void setup() {
pinMode(enA, OUTPUT);
pinMode(enB, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(57600);
Serial.print("#ihihuuho");
//MotorsForward();
}
void loop()
{
if (Serial.available() > 0)
{
}
while (Serial.available() > 0)
{ command = (Serial.read());
//Serial.println(" cmdd ");
//Serial.println(command);
//Serial.println("str: " + btdata);
if (command == '?')
{
//Serial.println();
//Serial.println("Command: " + btdata);
delay(1);
if (btdata.indexOf("forw") >= 0){
MotorsForward(255);
}
if (btdata.indexOf("back") >= 0){
MotorsBackward(255);
}
else{
Serial.println("Command not recognized: " + btdata);
}
btdata = "";
}
else if (command == '/')
{
//Serial.println();
//Serial.println("Direction: " + btdata);
dir = btdata.toInt();
btdata = "";
}
else if (command == '%')
{
//Serial.println();
Serial.println("Power: " + btdata);
power = btdata.toInt();
btdata = "";
if ( dir == 1 && power>0) {
MotorsForward(power);
}
else if ( dir == 5 && power>0) {
MotorsBackward(power);
}
else if ( dir == 7 && power>0) {
MotorsSpinR(power);
}
else if ( dir == 3 && power>0) {
MotorsSpinL(power);
}
else if ( dir == 8 && power>0) {
MotorsFR(power);
}
else if ( dir == 2 && power>0) {
MotorsFL(power);
}
else if ( dir == 4 && power>0) {
MotorsBL(power);
}
else if ( dir == 6 && power>0) {
MotorsBR(power);
}
else{
MotorsStop();
}
}
else{
btdata = btdata + command;
}
}
delay(500);
}
void LedBlue()
{
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
//delay(1000); // wait for a second
}
void LedRed()
{
digitalWrite(LED_BUILTIN, LOW); // turn the LED on (HIGH is the voltage level)
}
void MotorsBackward(int powa)
{
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
digitalWrite(in3, HIGH);
digitalWrite(in4, LOW);
analogWrite(enA, powa);
analogWrite(enB, powa);
}
void MotorsForward(int powa)
{
// Serial.println("Forward!");
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
digitalWrite(in3, LOW);
digitalWrite(in4, HIGH);
analogWrite(enA, powa);
analogWrite(enB, powa);
}
void MotorsSpinR(int powa)
{
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
digitalWrite(in3, LOW);
digitalWrite(in4, HIGH);
analogWrite(enA, powa);
analogWrite(enB, powa);
}
void MotorsSpinL(int powa)
{
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
digitalWrite(in3, HIGH);
digitalWrite(in4, LOW);
analogWrite(enA, powa);
analogWrite(enB, powa);
}
void MotorsFL(int powa)
{
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
digitalWrite(in3, LOW);
digitalWrite(in4, LOW);
analogWrite(enA, powa);
}
void MotorsFR(int powa)
{
digitalWrite(in1, LOW);
digitalWrite(in2, LOW);
digitalWrite(in3, LOW);
digitalWrite(in4, HIGH);
analogWrite(enB, powa);
}
void MotorsBR(int powa)
{
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
digitalWrite(in3, LOW);
digitalWrite(in4, LOW);
analogWrite(enA, powa);
}
void MotorsBL(int powa)
{
digitalWrite(in1, LOW);
digitalWrite(in2, LOW);
digitalWrite(in3, HIGH);
digitalWrite(in4, LOW);
analogWrite(enB, powa);
}
void MotorsStop()
{
// now turn off motors
digitalWrite(in1, LOW);
digitalWrite(in2, LOW);
digitalWrite(in3, LOW);
digitalWrite(in4, LOW);
}
Androidcode
Javapackage com.pj.hiro.hiro_control;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Handler;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import com.zerokol.views.JoystickView;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
//BT
private final String DEVICE_ADDRESS="Your BT module Mac Adress";
private final UUID PORT_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");//Serial Port Service ID
private BluetoothDevice device;
private BluetoothSocket socket;
private OutputStream outputStream;
private InputStream inputStream;
Button startButton, sendButton,clearButton,stopButton;
TextView textView;
EditText editText;
LinearLayout joystickLayout;
RelativeLayout bluetoothLayout;
boolean deviceConnected=false;
Thread thread;
FloatingActionButton fab;
byte buffer[];
int bufferPosition;
boolean stopThread;
//___
private TextView angleTextView;
private TextView powerTextView;
private TextView directionTextView;
// Importing also other views
private JoystickView joystick;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startButton = (Button) findViewById(R.id.buttonStart);
sendButton = (Button) findViewById(R.id.buttonSend);
clearButton = (Button) findViewById(R.id.buttonClear);
stopButton = (Button) findViewById(R.id.buttonStop);
editText = (EditText) findViewById(R.id.editText);
textView = (TextView) findViewById(R.id.textView);
bluetoothLayout = (RelativeLayout) findViewById(R.id.BluetoothLayout);
joystickLayout = (LinearLayout) findViewById(R.id.JoyStickLayout);
fab = (FloatingActionButton) findViewById(R.id.hider);
setUiEnabled(false);
// Set window fullscreen and remove title bar, and force landscape orientation
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
angleTextView = (TextView) findViewById(R.id.angleTextView);
powerTextView = (TextView) findViewById(R.id.powerTextView);
directionTextView = (TextView) findViewById(R.id.directionTextView);
//Referencing also other views
joystick = (JoystickView) findViewById(R.id.joystickView);
joystick.setOnJoystickMoveListener(new JoystickView.OnJoystickMoveListener() {
@Override
public void onValueChanged(int angle, int power, int direction) {
// TODO Auto-generated method stub
angleTextView.setText(" " + String.valueOf(angle) + "°");
powerTextView.setText(" " + String.valueOf(power) + "%");
if(outputStream != null) {
try {
outputStream.write((String.valueOf(direction) + "/" + String.valueOf(Math.round(power * 2.5)) + "%").getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
switch (direction) {
case JoystickView.FRONT:
directionTextView.setText("front_lab" + " " + direction);
break;
case JoystickView.FRONT_RIGHT:
directionTextView.setText("front_right_lab" + " " + direction);
break;
case JoystickView.RIGHT:
directionTextView.setText("right_lab" + " " + direction);
break;
case JoystickView.RIGHT_BOTTOM:
directionTextView.setText("right_bottom_lab" + " " + direction);
break;
case JoystickView.BOTTOM:
directionTextView.setText("bottom_lab" + " " + direction);
break;
case JoystickView.BOTTOM_LEFT:
directionTextView.setText("bottom_left_lab" + " " + direction);
break;
case JoystickView.LEFT:
directionTextView.setText("left_lab" + " " + direction);
break;
case JoystickView.LEFT_FRONT:
directionTextView.setText("left_front_lab" + " " + direction);
break;
default:
directionTextView.setText("center_lab" + " " + direction);
}
int polaR = 0;
int polaL = 0;
int thrustR = 0;
int thrustL = 0;
}
}, JoystickView.DEFAULT_LOOP_INTERVAL);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(bluetoothLayout.getVisibility()==View.GONE){
bluetoothLayout.setVisibility(View.VISIBLE);
}
else{
bluetoothLayout.setVisibility(View.GONE);
}
}
});
joystickLayout.setVisibility(View.GONE);
}
public void setUiEnabled(boolean bool)
{
startButton.setEnabled(!bool);
sendButton.setEnabled(bool);
stopButton.setEnabled(bool);
textView.setEnabled(bool);
}
public boolean BTinit()
{
boolean found=false;
BluetoothAdapter bluetoothAdapter=BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
Toast.makeText(getApplicationContext(),"Device doesnt Support Bluetooth",Toast.LENGTH_SHORT).show();
}
if(!bluetoothAdapter.isEnabled())
{
Intent enableAdapter = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableAdapter, 0);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();
if(bondedDevices.isEmpty())
{
Toast.makeText(getApplicationContext(),"Please Pair the Device first",Toast.LENGTH_SHORT).show();
}
else
{
for (BluetoothDevice iterator : bondedDevices)
{
if(iterator.getAddress().equals(DEVICE_ADDRESS))
{
device=iterator;
found=true;
break;
}
}
}
return found;
}
public boolean BTconnect()
{
boolean connected=true;
try {
socket = device.createRfcommSocketToServiceRecord(PORT_UUID);
socket.connect();
} catch (IOException e) {
e.printStackTrace();
connected=false;
}
if(connected)
{
try {
outputStream=socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
try {
inputStream=socket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
return connected;
}
public void onClickStart(View view) {
if(BTinit())
{
if(BTconnect())
{
setUiEnabled(true);
deviceConnected=true;
beginListenForData();
textView.append("\nConnection Opened!\n");
if(joystickLayout.getVisibility()==View.GONE){
joystickLayout.setVisibility(View.VISIBLE);
}
}
}
}
void beginListenForData()
{
final Handler handler = new Handler();
stopThread = false;
buffer = new byte[1024];
Thread thread = new Thread(new Runnable()
{
public void run()
{
while(!Thread.currentThread().isInterrupted() && !stopThread)
{
try
{
int byteCount = inputStream.available();
if(byteCount > 0)
{
byte[] rawBytes = new byte[byteCount];
inputStream.read(rawBytes);
final String string=new String(rawBytes,"UTF-8");
handler.post(new Runnable() {
public void run()
{
textView.append(string);
Toast.makeText(getApplicationContext(), "Reçu" + string, Toast.LENGTH_SHORT).show();
}
});
}
}
catch (IOException ex)
{
stopThread = true;
}
}
}
});
thread.start();
}
public void onClickSend(View view) {
String string = editText.getText().toString() + "?";
try {
outputStream.write(string.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
textView.append("\nSent Data:"+string+"\n");
}
public void onClickStop(View view) throws IOException {
stopThread = true;
outputStream.close();
inputStream.close();
socket.close();
setUiEnabled(false);
deviceConnected=false;
textView.append("\nConnection Closed!\n");
if(joystickLayout.getVisibility()==View.VISIBLE){
joystickLayout.setVisibility(View.GONE);
}
}
public void onClickClear(View view) {
textView.setText("");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
}
Comments