diff --git a/Algorithm/pid.c b/Algorithm/pid.c
new file mode 100644
index 0000000000000000000000000000000000000000..fd82c7a816215e3d8053244dfc8fa9b4a7294099
--- /dev/null
+++ b/Algorithm/pid.c
@@ -0,0 +1,68 @@
+/****************************************************************************
+ *  Copyright (C) 2018 RoboMaster.
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ ***************************************************************************/
+ 
+#include "pid.h"
+#include "motor.h"
+//#include <stdlib.h>
+
+/**
+  * @brief  init pid parameter
+  * @param  pid struct
+    @param  parameter
+  * @retval None
+  */
+void pid_init(pid_struct_t *pid,
+              float kp,
+              float ki,
+              float kd,
+              float i_max,
+              float out_max)
+{
+  pid->kp      = kp;
+  pid->ki      = ki;
+  pid->kd      = kd;
+  pid->i_max   = i_max;
+  pid->out_max = out_max;
+}
+
+/**
+  * @brief  pid calculation
+  * @param  pid struct
+    @param  reference value
+    @param  feedback value
+  * @retval calculation result
+  */
+float pid_calc(pid_struct_t *pid, float ref, float fdb)
+{
+  pid->ref = ref;
+  pid->fdb = fdb;
+  pid->err[1] = pid->err[0];
+  pid->err[0] = pid->ref - pid->fdb;
+	if(pid->err[0]>4096){pid->err[0] = pid->err[0] - 8192;}
+	if(pid->err[0]<-4096){pid->err[0] = pid->err[0] + 8192;}
+  
+  pid->p_out  = pid->kp * pid->err[0];
+  pid->i_out += pid->ki * pid->err[0];
+  pid->d_out  = pid->kd * pid->err[0] - pid->err[1];
+  LIMIT_MIN_MAX(pid->i_out, -pid->i_max, pid->i_max);
+  
+  pid->output = pid->p_out + pid->i_out + pid->d_out;
+  LIMIT_MIN_MAX(pid->output, -pid->out_max, pid->out_max);
+  return pid->output;
+}
+
+
diff --git a/Algorithm/pid.h b/Algorithm/pid.h
new file mode 100644
index 0000000000000000000000000000000000000000..69f6f47fe7fb8c3919d3e5cbe04127db84a6a511
--- /dev/null
+++ b/Algorithm/pid.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+ *  Copyright (C) 2018 RoboMaster.
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ ***************************************************************************/
+ 
+#ifndef _PID_H
+#define _PID_H
+
+#include "main.h"
+
+typedef struct _pid_struct_t
+{
+  float kp;
+  float ki;
+  float kd;
+  float i_max;
+  float out_max;
+  
+  float ref;      // target value
+  float fdb;      // feedback value
+  float err[2];   // error and last error
+
+  float p_out;
+  float i_out;
+  float d_out;
+  float output;
+}pid_struct_t;
+
+void pid_init(pid_struct_t *pid,
+              float kp,
+              float ki,
+              float kd,
+              float i_max,
+              float out_max);
+              
+float  pid_calc(pid_struct_t *pid, float ref, float fdb);
+
+#endif
diff --git a/Device/list_motor.c b/Device/list_motor.c
new file mode 100644
index 0000000000000000000000000000000000000000..1a000a3b2012f4a85c5e9815b07a4eae276d0ede
--- /dev/null
+++ b/Device/list_motor.c
@@ -0,0 +1,28 @@
+#include "motor.h"
+#include "oled.h"
+#include "list_motor.h"
+
+motor_t gm6020;
+const pid_struct_t M3508_pid_speed = {
+		2, 0.005, 2, 16000, 16000
+	};
+const pid_struct_t M3508_pid_pos = {
+		0.1, 0.005, 0, 16000, 16000
+	};
+
+const pid_struct_t GM6020_pid_speed = {
+		40, 3, 0, 30000, 30000
+	};
+const pid_struct_t GM6020_pid_pos = {
+		30, 4, 15, 10000, 10000
+	};
+
+void motors_init(void){
+	gm6020.type = GM6020;
+	gm6020.can_info.can_id = 0;
+	gm6020.can_info.tx_id = 1;
+	gm6020.can_info.rx_id = 0x205; 
+	gm6020.pid_pos = GM6020_pid_pos;
+	gm6020.pid_speed = GM6020_pid_speed;
+}
+
diff --git a/Device/list_motor.h b/Device/list_motor.h
new file mode 100644
index 0000000000000000000000000000000000000000..e0ea4d0b6a0c27ce464c840372ff066f9b448314
--- /dev/null
+++ b/Device/list_motor.h
@@ -0,0 +1,19 @@
+#include "motor.h"
+#include "oled.h"
+
+
+extern motor_t m3508_frontleft;
+extern motor_t m3508_frontright;
+extern motor_t m3508_backleft;
+extern motor_t m3508_backright;
+extern motor_t gm6020_down;
+extern motor_t gm6020_up;
+extern motor_t m2006;
+extern motor_t gm6020;
+
+extern const pid_struct_t M3508_pid_speed;
+extern const pid_struct_t M3508_pid_pos;
+extern const pid_struct_t GM6020_pid_speed;
+extern const pid_struct_t GM6020_pid_pos;
+
+void motors_init(void);
diff --git a/Device/motor.c b/Device/motor.c
new file mode 100644
index 0000000000000000000000000000000000000000..522851f1a2af350cf28f7f2e39a1e42c1be467fa
--- /dev/null
+++ b/Device/motor.c
@@ -0,0 +1,95 @@
+#include "motor.h"
+#include "oled.h"
+#include "pid.h"
+//#include "list_motor.h"
+
+void set_motor_voltage(uint8_t id, motor_t *motor1, motor_t *motor2, motor_t *motor3, motor_t *motor4) {
+    int16_t sp1, sp2, sp3, sp4;
+    uint16_t tx_id; //can_id était déclaré là mais pas utilisé
+    sp1 = sp2 = sp3 = sp4 = 0;
+    tx_id = id;
+
+    if (motor1) { sp1 = correct_output(motor1); }
+    if (motor2) { sp2 = correct_output(motor2); }
+    if (motor3) { sp3 = correct_output(motor3); }
+    if (motor4) { sp4 = correct_output(motor4); }
+		
+		can1_transmit(tx_id, sp1, sp2, sp3, sp4);
+}
+
+
+static int16_t correct_output(motor_t *motor) {
+    return motor->voltage;
+}
+
+
+static void get_6020_data(motor_t* motor, uint8_t buf[CAN_DATA_SIZE]){
+	motor->info.GM6020_info.angle = (int16_t)(buf[0] << 8 | buf[1]);
+	motor->info.GM6020_info.speed = (int16_t)(buf[2] << 8 | buf[3]);
+	motor->info.GM6020_info.current = (int16_t)(buf[4] << 8 | buf[5]);
+	motor->info.GM6020_info.temp = (int8_t)(buf[6]);
+	/*
+	oled_clear(Pen_Clear);
+	oled_printf(1,1,"Val: %i", motor->info.GM6020_info.angle);
+	*/
+}
+
+static void get_3508_data(motor_t* motor, uint8_t buf[CAN_DATA_SIZE]){
+	motor->info.M3508_info.angle = (int16_t)(buf[0] << 8 | buf[1]);
+	motor->info.M3508_info.speed = (int16_t)(buf[2] << 8 | buf[3]);
+	motor->info.M3508_info.current = (int16_t)(buf[4] << 8 | buf[5]);
+	motor->info.M3508_info.temp = (int8_t)(buf[6]);
+}
+
+void run_motor_from_command(motor_t *motor, pid_struct_t pid_param, float target, float fdb)
+{
+	
+	motor->voltage = pid_calc(&pid_param, target, fdb);
+}
+
+
+uint8_t get_motor_data(motor_t *motor) {
+    uint8_t buf[CAN_DATA_SIZE];
+    can1_read(motor->can_info.rx_id, buf);
+		
+	
+    switch (motor->type) {
+			case GM6020:
+				get_6020_data(motor, buf);
+				return 1;
+			case M3508:
+				get_3508_data(motor, buf);
+				return 1;
+			default:
+				return 0;
+    }
+}
+
+
+void set_motor_position(motor_t *motor)
+{
+	float target = motor->target;
+	switch(motor->type){
+		case M3508:
+				run_motor_from_command(motor, motor->pid_pos, target, motor->info.M3508_info.angle);
+		case GM6020:
+				run_motor_from_command(motor, motor->pid_pos, target, motor->info.GM6020_info.angle);
+		/*default:
+			bsp_error_handler(__FUNCTION__, __LINE__, "motor type undefined");*/
+	}
+
+}
+
+
+void set_motor_speed(motor_t *motor)
+{
+	float target = motor->target;
+	switch(motor->type){
+		case M3508:
+				run_motor_from_command(motor, motor->pid_speed, target, motor->info.M3508_info.speed);;
+		case GM6020:
+				run_motor_from_command(motor, motor->pid_speed, target, motor->info.GM6020_info.speed);;
+		/*default:
+			bsp_error_handler(__FUNCTION__, __LINE__, "motor type undefined");*/
+	}
+}
diff --git a/Device/motor.h b/Device/motor.h
new file mode 100644
index 0000000000000000000000000000000000000000..53b8dfc0c7c045a5d13418e2e7438ac2e9b1bd94
--- /dev/null
+++ b/Device/motor.h
@@ -0,0 +1,88 @@
+#ifndef _MOTOR_H_
+#define _MOTOR_H_
+
+#include "bsp_can.h"
+#include "bsp_pwm.h"
+#include "pid.h"
+
+
+#define CAN_TX1_ID 0x200
+#define CAN_TX2_ID 0x1FF
+
+#define CAN_RX1_START 0x201
+#define CAN_RX2_START 0x205
+
+enum motors {
+	/* can motors */
+	M3508,
+	GM6020,
+	M2006,
+	general_motor,
+	/* pwm motors */
+	M2305,
+};
+//
+
+typedef struct {    
+    uint16_t    rx_id;
+    uint16_t    tx_id;
+    uint8_t     can_id;
+}   can_info_t;
+
+
+
+/**
+ * @struct  GM6020_info_t
+ * @brief   store GM6020 motor data
+ * @var rx_id   sensor CAN receive id
+ * @var tx_id   sensor CAN transmit id
+ * @var can_id  CAN id chosen from [CAN1, CAN2]
+ * @var angle       most recent angle data
+ * @var current_get actual current / torque output
+ * @var current_set target current / torque output
+ */
+typedef struct {    
+    int16_t     angle;
+    int16_t     speed;
+    int16_t     current;
+		int8_t			temp;
+}   GM6020_info_t;
+
+typedef struct {    
+    int16_t     angle;
+    int16_t     speed;
+    int16_t     current;
+		int8_t			temp;
+}   M3508_info_t;
+
+typedef union{
+	GM6020_info_t GM6020_info;
+	M3508_info_t M3508_info;
+} motor_info_t;
+
+
+// Une struct par moteur
+typedef struct
+{
+	can_info_t can_info;	// Can ID information
+	//M3508_info_t info;
+	motor_info_t info;		// Specific info about the motor
+	int type; 		// Type du moteur, ex:GM6020
+	pid_struct_t pid_pos;			// Controler
+	pid_struct_t pid_speed;			// Controler
+	float target;
+	float voltage;
+} motor_t;
+	
+//id:0 -> 0x200, 1 -> 0x1ff
+void set_motor_voltage(uint8_t id, motor_t *motor1, motor_t *motor2, motor_t *motor3, motor_t *motor4);
+
+static int16_t correct_output(motor_t *motor);
+uint8_t get_motor_data(motor_t *motor);
+static void get_6020_data(motor_t* motor, uint8_t buf[CAN_DATA_SIZE]);
+
+void set_motor_position(motor_t *motor);
+void set_motor_speed(motor_t *motor);
+void run_motor_from_command(motor_t *motor, pid_struct_t pid_param, float target, float fdb);
+
+#endif
diff --git a/Driver/bsp_can.c b/Driver/bsp_can.c
new file mode 100644
index 0000000000000000000000000000000000000000..9fdc845f2cbffa822fa962db42092f4cdc45155c
--- /dev/null
+++ b/Driver/bsp_can.c
@@ -0,0 +1,116 @@
+/****************************************************************************
+ *  Copyright (C) 2018 RoboMaster.
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ ***************************************************************************/
+ 
+#include "bsp_can.h"
+#include "bsp_led.h"
+
+uint16_t can_cnt;
+uint8_t can1_rx_buffer[MOTOR_MAX_NUM][CAN_DATA_SIZE];
+
+/**
+  * @brief  init can filter, start can, enable can rx interrupt
+  * @param  hcan pointer to a CAN_HandleTypeDef structure that contains
+  *         the configuration information for the specified CAN.
+  * @retval None
+  */
+void can_user_init(CAN_HandleTypeDef* hcan )
+{
+  CAN_FilterTypeDef  can_filter;
+
+  can_filter.FilterBank = 0;                       // filter 0
+  can_filter.FilterMode =  CAN_FILTERMODE_IDMASK;  // mask mode
+  can_filter.FilterScale = CAN_FILTERSCALE_32BIT;
+  can_filter.FilterIdHigh = 0;
+  can_filter.FilterIdLow  = 0;
+  can_filter.FilterMaskIdHigh = 0;
+  can_filter.FilterMaskIdLow  = 0;                // set mask 0 to receive all can id
+  can_filter.FilterFIFOAssignment = CAN_RX_FIFO0; // assign to fifo0
+  can_filter.FilterActivation = ENABLE;           // enable can filter
+  can_filter.SlaveStartFilterBank  = 14;          // only meaningful in dual can mode
+   
+  HAL_CAN_ConfigFilter(hcan, &can_filter);        // init can filter
+  HAL_CAN_Start(&hcan1);                          // start can1
+  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING); // enable can1 rx interrupt
+}
+
+/**
+  * @brief  can rx callback, get motor feedback info
+  * @param  hcan pointer to a CAN_HandleTypeDef structure that contains
+  *         the configuration information for the specified CAN.
+  * @retval None
+  */
+void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
+{
+	CAN_RxHeaderTypeDef rx_header;
+	/* get device id ahead of time */
+	rx_header.StdId = (CAN_RI0R_STID & hcan->Instance->sFIFOMailBox[CAN_RX_FIFO0].RIR) >> CAN_TI0R_STID_Pos;
+	
+  if(hcan->Instance == CAN1)
+  {
+		if ((rx_header.StdId >= FEEDBACK_ID_BASE) && (rx_header.StdId <  FEEDBACK_ID_BASE + MOTOR_MAX_NUM)) // judge the can id
+		{
+			can_cnt ++;
+			uint8_t index = rx_header.StdId - FEEDBACK_ID_BASE; // get motor index by can_id
+			HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, can1_rx_buffer[index]); //receive can data
+		}
+	}
+  if (can_cnt == 500)
+  {
+    can_cnt = 0;
+    LED_GREEN_TOGGLE(); // green led blink indicate can comunication successful 
+  }
+}
+
+
+
+void can1_transmit(uint16_t id, int16_t msg1, int16_t msg2, int16_t msg3, int16_t msg4) {
+    can_transmit(id, msg1, msg2, msg3, msg4);
+}
+
+void can1_read(uint16_t id, uint8_t buf[CAN_DATA_SIZE]) {
+    uint8_t idx = id - FEEDBACK_ID_BASE;
+    memcpy(buf, can1_rx_buffer[idx], CAN_DATA_SIZE);
+}
+
+/**
+  * @brief  send motor control message through can bus
+  * @param  id_range to select can control id 0x1ff or 0x2ff
+  * @param  motor voltage 1,2,3,4 or 5,6,7
+  * @retval None
+  */
+void can_transmit(uint8_t id, int16_t val1, int16_t val2, int16_t val3, int16_t val4)
+{
+  CAN_TxHeaderTypeDef tx_header;
+  uint8_t             tx_data[8];
+    
+  tx_header.StdId = (id == 0)?(0x200):(0x1ff);
+  tx_header.IDE   = CAN_ID_STD;
+  tx_header.RTR   = CAN_RTR_DATA;
+  tx_header.DLC   = 8;
+	tx_header.TransmitGlobalTime = DISABLE;
+
+  tx_data[0] = (val1>>8)&0xff;
+  tx_data[1] =    (val1)&0xff;
+  tx_data[2] = (val2>>8)&0xff;
+  tx_data[3] =    (val2)&0xff;
+  tx_data[4] = (val3>>8)&0xff;
+  tx_data[5] =    (val3)&0xff;
+  tx_data[6] = (val4>>8)&0xff;
+  tx_data[7] =    (val4)&0xff;
+  HAL_CAN_AddTxMessage(&hcan1, &tx_header, tx_data,(uint32_t*)CAN_TX_MAILBOX0); 
+}
+
diff --git a/Driver/bsp_can.h b/Driver/bsp_can.h
new file mode 100644
index 0000000000000000000000000000000000000000..7f8b125909ff05b403ebb1c1a3f672c84ba126da
--- /dev/null
+++ b/Driver/bsp_can.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+ *  Copyright (C) 2018 RoboMaster.
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ ***************************************************************************/
+
+#ifndef __BSP_CAN
+#define __BSP_CAN
+
+#include "can.h"
+#include <stdio.h>
+#include <string.h>
+
+#define FEEDBACK_ID_BASE      0x204
+#define CAN_CONTROL_ID_BASE   0x200
+#define CAN_CONTROL_ID_EXTEND 0x1ff
+#define MOTOR_MAX_NUM         7
+#define CAN_DATA_SIZE       8
+
+typedef struct
+{
+    uint16_t can_id;
+    int16_t  set_voltage;
+    uint16_t rotor_angle;
+    int16_t  rotor_speed;
+    int16_t  torque_current;
+    uint8_t  temp;
+}moto_info_t;
+
+void can_user_init(CAN_HandleTypeDef* hcan);
+void can1_transmit(uint16_t id, int16_t val1, int16_t val2, int16_t val3, int16_t val4);
+void can1_read(uint16_t id, uint8_t buf[CAN_DATA_SIZE]);
+void can_transmit(uint8_t id_range, int16_t val1, int16_t val2, int16_t val3, int16_t val4);
+#endif
diff --git a/Driver/bsp_key.c b/Driver/bsp_key.c
new file mode 100644
index 0000000000000000000000000000000000000000..a3e90b674993326bbd96685f5b67bdd9d6cb0877
--- /dev/null
+++ b/Driver/bsp_key.c
@@ -0,0 +1,40 @@
+/****************************************************************************
+ *  Copyright (C) 2018 RoboMaster.
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ ***************************************************************************/
+ 
+#include "bsp_key.h"
+
+/**
+  * @brief  detect key presse down event
+  * @param  None
+  * @retval event flag
+  */
+uint8_t key_scan(void)
+{
+  static uint8_t key_last = 0;
+  static uint8_t key = 0;
+  
+  key_last = key;
+  key = HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin);
+  if( (key == GPIO_PIN_RESET) && (key_last == GPIO_PIN_SET))
+  {
+    return 1;
+  }
+  else
+  {
+    return 0;
+  }
+}
diff --git a/Driver/bsp_key.h b/Driver/bsp_key.h
new file mode 100644
index 0000000000000000000000000000000000000000..00ca3f2885854b421d7a23fd521d218dd65cb7aa
--- /dev/null
+++ b/Driver/bsp_key.h
@@ -0,0 +1,24 @@
+/****************************************************************************
+ *  Copyright (C) 2018 RoboMaster.
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ ***************************************************************************/
+
+#ifndef __BSP_KEY
+#define __BSP_KEY
+
+#include "gpio.h"
+
+uint8_t key_scan(void);
+#endif
diff --git a/Driver/bsp_led.h b/Driver/bsp_led.h
new file mode 100644
index 0000000000000000000000000000000000000000..b4181c4af0461618cab65cfc32e282aa8eed1577
--- /dev/null
+++ b/Driver/bsp_led.h
@@ -0,0 +1,31 @@
+/****************************************************************************
+ *  Copyright (C) 2018 RoboMaster.
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ ***************************************************************************/
+ 
+#ifndef __BSP_LED
+#define __BSP_LED
+
+#define LED_GREEN_ON()     HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_RESET)
+#define LED_GREEN_OFF()    HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_SET)
+#define LED_GREEN_TOGGLE() LED_GREEN_GPIO_Port->ODR ^= LED_GREEN_Pin
+     
+#define LED_RED_ON()       HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, GPIO_PIN_RESET)
+#define LED_RED_OFF()      HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, GPIO_PIN_SET)
+#define LED_RED_TOGGLE()   LED_RED_GPIO_Port->ODR ^= LED_RED_Pin
+     
+#define LED_ALL_OFF        LED_RED_OFF(); LED_RED_OFF();
+
+#endif
diff --git a/Driver/bsp_pwm.c b/Driver/bsp_pwm.c
index f1b8811504419addcc63721740ecc215648de187..36d4cf4e4218db957fe37a7a08e5b4bd1c2fa7d3 100644
--- a/Driver/bsp_pwm.c
+++ b/Driver/bsp_pwm.c
@@ -1,28 +1,85 @@
-#include "tim.h"
+/****************************************************************************
+ *  Copyright (C) 2018 RoboMaster.
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ ***************************************************************************/
+
 #include "bsp_pwm.h"
 
-void PWM_init(void){
-	/* Open 4 sets of PWM waves respectively */
-		/**TIM2 GPIO Configuration    
-	PA8     ------> TIM2_CH1
-	PA9     ------> TIM2_CH2
-	PA10    ------> TIM2_CH3
-	PA11    ------> TIM2_CH4 
-	*/
-	HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
-	HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
-	HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3);
-	HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_4);
+/**
+  * @brief  start pwm output
+  * @param  None
+  * @retval None
+  */
+void pwm_init(void)
+{
+    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // start pwm output
+    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
+    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
+    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4);
 }
 
+/**
+  * @brief  sets PWM duty cycle (= speed) for a particular channel
+  * @param  Timer, channel (1 to 4), duty cycle (between 0 and 1)
+  * @retval None
+  */
 void PWM_SetDuty(TIM_HandleTypeDef *tim,uint32_t tim_channel,float duty){
-	
+	duty = duty/10 + 0.10f; //rescale before send
 	switch(tim_channel){	
 		case TIM_CHANNEL_1: tim->Instance->CCR1 = (PWM_RESOLUTION*duty) - 1;break;
 		case TIM_CHANNEL_2: tim->Instance->CCR2 = (PWM_RESOLUTION*duty) - 1;break;
 		case TIM_CHANNEL_3: tim->Instance->CCR3 = (PWM_RESOLUTION*duty) - 1;break;
 		case TIM_CHANNEL_4: tim->Instance->CCR4 = (PWM_RESOLUTION*duty) - 1;break;
 	}
+}
+
+/**
+  * @brief  sets PWM duty cycle (= speed) for a all channels
+  * @param  Timer, duty cycles (between 0 and 1)
+  * @retval None
+  */
+void PWM_SetAllDuty(TIM_HandleTypeDef *tim, float duty_ch1, float duty_ch2, float duty_ch3, float duty_ch4){
+	duty_ch1 = duty_ch1/10 + 0.10f; //rescale before send
+	duty_ch2 = duty_ch2/10 + 0.10f;
+	duty_ch3 = duty_ch3/10 + 0.10f;
+	duty_ch4 = duty_ch4/10 + 0.10f;
+	tim->Instance->CCR1 = (PWM_RESOLUTION*duty_ch1) - 1;
+	tim->Instance->CCR2 = (PWM_RESOLUTION*duty_ch2) - 1;
+	tim->Instance->CCR3 = (PWM_RESOLUTION*duty_ch3) - 1;
+	tim->Instance->CCR4 = (PWM_RESOLUTION*duty_ch4) - 1;
 	
 }
 
+/**
+  * @brief  scales all PWM duty cycles between 0 and 1
+  * @param  Timer
+  * @retval None
+  */
+void PWM_ScaleAll(TIM_HandleTypeDef *tim){ //il faudrait jouer sur l'allumage des ports d'alimentation des snails (voir Nathan pour plus de détails)
+	tim->Instance->CCR1 = (PWM_RESOLUTION*0.2) - 1;
+	tim->Instance->CCR2 = (PWM_RESOLUTION*0.2) - 1;
+	tim->Instance->CCR3 = (PWM_RESOLUTION*0.2) - 1;
+	tim->Instance->CCR4 = (PWM_RESOLUTION*0.2) - 1;
+	
+	HAL_Delay(3500);
+	
+	tim->Instance->CCR1 = (PWM_RESOLUTION*0.1) - 1;
+	tim->Instance->CCR2 = (PWM_RESOLUTION*0.1) - 1;
+	tim->Instance->CCR3 = (PWM_RESOLUTION*0.1) - 1;
+	tim->Instance->CCR4 = (PWM_RESOLUTION*0.1) - 1;
+	
+	HAL_Delay(500);
+	
+}
diff --git a/Driver/bsp_pwm.h b/Driver/bsp_pwm.h
index 003055602ac6c9fe83b916bc3ffadb7b68a1a476..0beb2398c189d8430ccd5b9efd375b2d775cd144 100644
--- a/Driver/bsp_pwm.h
+++ b/Driver/bsp_pwm.h
@@ -1,8 +1,28 @@
+/****************************************************************************
+ *  Copyright (C) 2018 RoboMaster.
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ ***************************************************************************/
+ 
 #ifndef __BSP_PWM
 #define __BSP_PWM
 
-#include "main.h"
+#include "tim.h"
 
+void pwm_init(void);
 void PWM_SetDuty(TIM_HandleTypeDef *tim,uint32_t tim_channel,float duty);
-void PWM_init(void);
+void PWM_SetAllDuty(TIM_HandleTypeDef *tim, float duty_ch1, float duty_ch2, float duty_ch3, float duty_ch4);
+void PWM_ScaleAll(TIM_HandleTypeDef *tim);
+
 #endif