Skip to content

Commit

Permalink
Add submodules
Browse files Browse the repository at this point in the history
  • Loading branch information
araffin committed Apr 6, 2018
1 parent 5a95b51 commit 0d05712
Show file tree
Hide file tree
Showing 11 changed files with 475 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bin/
*.log
9 changes: 9 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[submodule "rust-arduino-serial"]
path = rust-arduino-serial
url = https://github.com/araffin/rust-arduino-serial
[submodule "cpp-arduino-serial"]
path = cpp-arduino-serial
url = https://github.com/araffin/cpp-arduino-serial.git
[submodule "python-arduino-serial"]
path = python-arduino-serial
url = https://github.com/araffin/python-arduino-serial.git
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Robust Arduino Serial Protocol

**Robust Arduino Serial** is a simple and robust serial communication protocol. It was designed to make two Arduinos communicate, but can also be useful when you want a computer (e.g. a Raspberry Pi) to communicate with an Arduino.

**Please read the [Medium Article](https://medium.com/@araffin/simple-and-robust-computer-arduino-serial-communication-f91b95596788) to have an overview of this protocol.**

Implementations are available for:

- Arduino (`arduino-serial/` folder)
- [Python](https://github.com/araffin/python-arduino-serial)
- [C++](https://github.com/araffin/cpp-arduino-serial)
- [Rust](https://github.com/araffin/rust-arduino-serial)


**Examples** are provided in each repository.

### Arduino Implementation

Recommended: Arduino-Makefile
```
sudo apt-get install arduino-mk
```

Compile and upload the code to the Arduino (please check the board name in the Makefile):
```
cd arduino-board/
make
make upload
```

### Python Implementation

[![Build Status](https://travis-ci.org/araffin/python-arduino-serial.svg?branch=master)](https://travis-ci.org/araffin/python-arduino-serial)

Python repository: [https://github.com/araffin/python-arduino-serial]((https://github.com/araffin/python-arduino-serial)

### C++ Implementation

[![Build Status](https://travis-ci.org/araffin/cpp-arduino-serial.svg?branch=master)](https://travis-ci.org/araffin/cpp-arduino-serial)


C++ repository: [https://github.com/araffin/cpp-arduino-serial]((https://github.com/araffin/cpp-arduino-serial)


### Rust Implementation

[![Build Status](https://travis-ci.org/araffin/rust-arduino-serial.svg?branch=master)](https://travis-ci.org/araffin/rust-arduino-serial) [![Build status](https://ci.appveyor.com/api/projects/status/h0ejgesat0nnpahc/branch/master?svg=true)](https://ci.appveyor.com/project/araffin/rust-arduino-serial/branch/master)

Rust repository: [https://github.com/araffin/rust-arduino-serial]((https://github.com/araffin/rust-arduino-serial)
72 changes: 72 additions & 0 deletions arduino-board/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
### DISCLAIMER
### This is an example Makefile and it MUST be configured to suit your needs.
### For detailled explanations about all the avalaible options,
### please refer to https://github.com/sudar/Arduino-Makefile/blob/master/arduino-mk-vars.md
### Original project where this Makefile comes from: https://github.com/WeAreLeka/Bare-Arduino-Project

### PROJECT_DIR
### This is the path to where you have created/cloned your project
PROJECT_DIR = $(shell pwd)

### ARDMK_DIR
### Path to the Arduino-Makefile directory.
ARDMK_DIR = /usr/share/arduino

### ARDUINO_DIR
### Path to the Arduino application and ressources directory.

### or on Linux: (remove the one you don't want)
ARDUINO_DIR = /usr/share/arduino

### USER_LIB_PATH
### Path to where the your project's libraries are stored.
USER_LIB_PATH := $(PROJECT_DIR)/lib

### BOARD_TAG
### It must be set to the board you are currently using. (i.e uno, mega2560, etc.)
BOARD_TAG = uno

### MONITOR_BAUDRATE
### It must be set to Serial baudrate value you are using.
MONITOR_BAUDRATE = 115200

### AVR_TOOLS_DIR
### Path to the AVR tools directory such as avr-gcc, avr-g++, etc.
### On OS X with `homebrew`:
AVR_TOOLS_DIR = /usr/local
### or on Linux: (remove the one you don't want)
AVR_TOOLS_DIR = /usr

### AVRDDUDE
### Path to avrdude directory.
### On OS X with `homebrew`:
AVRDDUDE = /usr/local/bin/avrdude
### or on Linux: (remove the one you don't want)
AVRDDUDE = /usr/bin/avrdude

### CFLAGS_STD
### Set the C standard to be used during compilation. Documentation (https://github.com/WeAreLeka/Arduino-Makefile/blob/std-flags/arduino-mk-vars.md#cflags_std)
CFLAGS_STD = -std=gnu11

### CXXFLAGS_STD
### Set the C++ standard to be used during compilation. Documentation (https://github.com/WeAreLeka/Arduino-Makefile/blob/std-flags/arduino-mk-vars.md#cxxflags_std)
CXXFLAGS_STD = -std=gnu++11

### CXXFLAGS
### Flags you might want to set for debugging purpose. Comment to stop.
CXXFLAGS += -pedantic -Wall -Wextra

### MONITOR_PORT
### The port your board is connected to. Using an '*' tries all the ports and finds the right one.
MONITOR_PORT = /dev/ttyACM*

### CURRENT_DIR
### Do not touch - used for binaries path
CURRENT_DIR = $(shell basename $(CURDIR))

### OBJDIR
### This is were you put the binaries you just compile using 'make'
OBJDIR = $(PROJECT_DIR)/bin/$(BOARD_TAG)/$(CURRENT_DIR)

### path to Arduino.mk, inside the ARDMK_DIR, don't touch.
include $(ARDMK_DIR)/Arduino.mk
17 changes: 17 additions & 0 deletions arduino-board/order.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef ORDER_H
#define ORDER_H

// Define the orders that can be sent and received
enum Order {
HELLO = 0,
SERVO = 1,
MOTOR = 2,
ALREADY_CONNECTED = 3,
ERROR = 4,
RECEIVED = 5,
STOP = 6,
};

typedef enum Order Order;

#endif
17 changes: 17 additions & 0 deletions arduino-board/parameters.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef PARAMETERS_H
#define PARAMETERS_H

#define SERIAL_BAUD 115200 // Baudrate
#define MOTOR_PIN 3
#define DIRECTION_PIN 4
#define SERVOMOTOR_PIN 6
#define INITIAL_THETA 110 // Initial angle of the servomotor
// Min and max values for motors
#define THETA_MIN 60
#define THETA_MAX 150
#define SPEED_MAX 100

// If DEBUG is set to true, the arduino will send back all the received messages
#define DEBUG false

#endif
215 changes: 215 additions & 0 deletions arduino-board/slave.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
#include <Arduino.h>
#include <Servo.h>

#include "order.h"
#include "slave.h"
#include "parameters.h"

bool is_connected = false; ///< True if the connection with the master is available
int8_t motor_speed = 0;
int16_t servo_angle = INITIAL_THETA;
Servo servomotor;

void setup()
{
// Init Serial
Serial.begin(SERIAL_BAUD);

// Init Motor
pinMode(MOTOR_PIN, OUTPUT);
pinMode(DIRECTION_PIN, OUTPUT);
// Stop the car
stop();

// Init Servo
servomotor.attach(SERVOMOTOR_PIN);
// Order between 0 and 180
servomotor.write(INITIAL_THETA);

// Wait until the arduino is connected to master
while(!is_connected)
{
write_order(HELLO);
wait_for_bytes(1, 1000);
get_messages_from_serial();
}

}

void loop()
{
get_messages_from_serial();
update_motors_orders();
}

void update_motors_orders()
{
servomotor.write(constrain(servo_angle, THETA_MIN, THETA_MAX));
motor_speed = constrain(motor_speed, -SPEED_MAX, SPEED_MAX);
// Send motor speed order
if (motor_speed > 0)
{
digitalWrite(DIRECTION_PIN, LOW);
}
else
{
digitalWrite(DIRECTION_PIN, HIGH);
}
analogWrite(MOTOR_PIN, convert_to_pwm(float(motor_speed)));
}

void stop()
{
analogWrite(MOTOR_PIN, 0);
digitalWrite(DIRECTION_PIN, LOW);
}

int convert_to_pwm(float motor_speed)
{
// TODO: compensate the non-linear dependency speed = f(PWM_Value)
return (int) round(abs(motor_speed)*(255./100.));
}

void get_messages_from_serial()
{
if(Serial.available() > 0)
{
// The first byte received is the instruction
Order order_received = read_order();

if(order_received == HELLO)
{
// If the cards haven't say hello, check the connection
if(!is_connected)
{
is_connected = true;
write_order(HELLO);
}
else
{
// If we are already connected do not send "hello" to avoid infinite loop
write_order(ALREADY_CONNECTED);
}
}
else if(order_received == ALREADY_CONNECTED)
{
is_connected = true;
}
else
{
switch(order_received)
{
case STOP:
{
motor_speed = 0;
stop();
if(DEBUG)
{
write_order(STOP);
}
break;
}
case SERVO:
{
servo_angle = read_i16();
if(DEBUG)
{
write_order(SERVO);
write_i16(servo_angle);
}
break;
}
case MOTOR:
{
// between -100 and 100
motor_speed = read_i8();
if(DEBUG)
{
write_order(MOTOR);
write_i8(motor_speed);
}
break;
}
// Unknown order
default:
write_order(ERROR);
write_i16(404);
return;
}
}
write_order(RECEIVED); // Confirm the reception
}
}


Order read_order()
{
return (Order) Serial.read();
}

void wait_for_bytes(int num_bytes, unsigned long timeout)
{
unsigned long startTime = millis();
//Wait for incoming bytes or exit if timeout
while ((Serial.available() < num_bytes) && (millis() - startTime < timeout)){}
}

// NOTE : Serial.readBytes is SLOW
// this one is much faster, but has no timeout
void read_signed_bytes(int8_t* buffer, size_t n)
{
size_t i = 0;
int c;
while (i < n)
{
c = Serial.read();
if (c < 0) break;
*buffer++ = (int8_t) c; // buffer[i] = (int8_t)c;
i++;
}
}

int8_t read_i8()
{
wait_for_bytes(1, 100); // Wait for 1 byte with a timeout of 100 ms
return (int8_t) Serial.read();
}

int16_t read_i16()
{
int8_t buffer[2];
wait_for_bytes(2, 100); // Wait for 2 bytes with a timeout of 100 ms
read_signed_bytes(buffer, 2);
return (((int16_t) buffer[0]) & 0xff) | (((int16_t) buffer[1]) << 8 & 0xff00);
}

int32_t read_i32()
{
int8_t buffer[4];
wait_for_bytes(4, 200); // Wait for 4 bytes with a timeout of 200 ms
read_signed_bytes(buffer, 4);
return (((int32_t) buffer[0]) & 0xff) | (((int32_t) buffer[1]) << 8 & 0xff00) | (((int32_t) buffer[2]) << 16 & 0xff0000) | (((int32_t) buffer[3]) << 24 & 0xff000000);
}

void write_order(enum Order myOrder)
{
uint8_t* Order = (uint8_t*) &myOrder;
Serial.write(Order, sizeof(uint8_t));
}

void write_i8(int8_t num)
{
Serial.write(num);
}

void write_i16(int16_t num)
{
int8_t buffer[2] = {(int8_t) (num & 0xff), (int8_t) (num >> 8)};
Serial.write((uint8_t*)&buffer, 2*sizeof(int8_t));
}

void write_i32(int32_t num)
{
int8_t buffer[4] = {(int8_t) (num & 0xff), (int8_t) (num >> 8 & 0xff), (int8_t) (num >> 16 & 0xff), (int8_t) (num >> 24 & 0xff)};
Serial.write((uint8_t*)&buffer, 4*sizeof(int8_t));
}
Loading

0 comments on commit 0d05712

Please sign in to comment.