【meArm机械臂】第二篇·Arduino控制程序

2023-05-16

系列文章目录

【meArm机械臂】第一篇·结构设计及搭建
【meArm机械臂】第二篇·Arduino控制程序

文章目录

  • 系列文章目录
  • 前言
  • 一、测试程序
    • 1.单个电机测试程序
    • 2.四舵机控制测试程序
    • 3.极限位置测量
  • 二、基本控制程序
  • 三、最终控制程序
  • 总结


前言

基于Arduino的机械臂控制程序,可以实现机械臂各个关节的位置初始化、特定位置抓取、手柄方式控制、蓝牙远程控制等功能,该程序是看太极创客教学视频时学的,我对于程序的部分内容进行了优化及改进,视频教程在此。


一、测试程序

1.单个电机测试程序

该测试程序是对单个电机进行测试的程序,SG90舵机的转角范围为0°-180°,将舵机连接到Arduino的TestPin引脚上,将该程序上传到Arduino上后,电机应该可以进行从0到180的转动。

#include<Servo.h>

Servo TestMotor;
#define TestPin 10

void setup() {
  // put your setup code here, to run once:
  TestMotor.attach(TestPin);
  delay(200);
}

void loop() {
  // put your main code here, to run repeatedly:
  for(int i=0;i++;i<180){
    TestMotor.write(i);
    delay(10);
  }
  for(int j=180;j--;j>0){
    TestMotor.write(j);
    delay(10);
  }
}

2.四舵机控制测试程序

将底盘舵机连接到11号引脚、大臂舵机连接到10号引脚、小臂舵机连接到9号引脚,钳子舵机连接到6号引脚(这些引脚都是PWM引脚),并将该程序上传给arduino,通过串口监视器输入控制指令,可以实现四个舵机的位置控制。

指令格式

b135:将底盘舵机旋转到135°的位置
r60:将大臂舵机旋转到60°的位置
f120:将小臂舵机旋转刀120°的位置
c60:将钳子舵机旋转到60°的位置
输入其他命令则会报错

#include<Servo.h>

Servo base,fArm,rArm,claw;

int dataIndex=0;

void setup() {
  // put your setup code here, to run once:
  base.attach(11);
  rArm.attach(10);
  fArm.attach(9);
  claw.attach(6);
  Serial.begin(9600);
  Serial.println("Please input serial data.");
}

void loop() {
  // put your main code here, to run repeatedly:
  if(Serial.available()>0){
    char servoName=Serial.read();//获取电机指令中的电机编号信息,因为read函数按字节读取

    Serial.print("servoName = ");
    Serial.print(servoName);
    Serial.print(" , ");

    int data=Serial.parseInt();//获取角度信息

    switch(servoName){
      case 'b':
        base.write(data);
        Serial.print("Set base servo value: ");
        Serial.println(data);
        break;
      case 'r':
        rArm.write(data);
        Serial.print("Set rArm servo value: ");
        Serial.println(data);
        break;
      case 'f':
        fArm.write(data);
        Serial.print("Set fArm servo value: ");
        Serial.println(data);
        break;
      case 'c':
        claw.write(data);
        Serial.print("Set claw servo value: ");
        Serial.println(data);
        break;
      default:
        Serial.println("Input ERROR!Please Input repeatly!");
        break;
    }
  }
}

3.极限位置测量

由于机械结构和舵机自身的问题,每个舵机都有自己的最大极限角和最小极限角,需要通过该程序测量出每个舵机的极限位置并存放在相应的常量中,要注意需要留出一定的裕量

参数说明:

const int baseMin:底盘舵机最小转角
const int baseMax:底盘舵机最大转角
const int rArmMin:大臂舵机最小转角
const int rArmMax:大臂舵机最大转角
const int fArmMin:小臂舵机最小转角
const int fArmMax:小臂舵机最大转角
const int clawMin:钳子舵机最小转角
const int clawMax:钳子舵机最大转角

/*该函数主要用来测试出各个电机的极限转角位置*/
#include<Servo.h>
Servo base,fArm,rArm,claw;

//建立4个int型变量存储当前电机角度值,设定初始值
int basePos=90;
int rArmPos=90;
int fArmPos=90;
int clawPos=90;

//存储电机极限值
const int baseMin=0;
const int baseMax=180;
const int rArmMin=45;//留一定裕度空间
const int rArmMax=180;
const int fArmMin=50;
const int fArmMax=120;
const int clawMin=40;
const int clawMax=90;

void setup() {
  // put your setup code here, to run once:
  base.attach(11);
  delay(200);
  rArm.attach(10);
  delay(200);
  fArm.attach(9);
  delay(200);
  claw.attach(6);
  delay(200);
  Serial.begin(9600);
  Serial.println("Welcome to meArm from K.Fire");
}

void loop() {
  // put your main code here, to run repeatedly:
  if(Serial.available()>0){
    char serialCmd=Serial.read();
    armDataCmd(serialCmd);//实现电机按转角旋转的函数
  }

  base.write(basePos);
  delay(10);
  fArm.write(fArmPos);
  delay(10);
  rArm.write(rArmPos);
  delay(10);
  claw.write(clawPos);
  delay(10);
  //如果设置某个电机角度则产生旋转,否则将保持初值
}



void armDataCmd(char serialCmd){//实现电机按转角旋转的函数
  Serial.print("serialCmd = ");
  Serial.print(serialCmd);

  int servoData = Serial.parseInt();//读取指令中的电机转角
  switch(serialCmd){
    case 'b':
      basePos = servoData;
      Serial.print(" Set base servo value: ");
      Serial.println(servoData);
      break;
    case 'r':
      rArmPos = servoData;
      Serial.print(" Set rArm servo value: ");
      Serial.println(servoData);
      break;
    case 'f':
      fArmPos = servoData;
      Serial.print(" Set fArm servo value: ");
      Serial.println(servoData);
      break;
    case 'c':
      clawPos = servoData;
      Serial.print(" Set claw servo value: ");
      Serial.println(servoData);
      break;
    default:
      Serial.println("Input ERROR!Please Input repeatly!");
      break;
  }
}

二、基本控制程序

该程序可以通过输入舵机旋转指令,控制舵机的旋转,如果输入的转角超出舵机的转角限制范围则会报错,输入错误指令也会报错,也可以通过输入特定的字母控制机械臂完成相应的动作。

指令格式及说明

b135:将底盘舵机旋转到135°的位置
r60:将大臂舵机旋转到60°的位置
f120:将小臂舵机旋转刀120°的位置
c60:将钳子舵机旋转到60°的位置
i:输出各个电机的转角状态及参数信息
g:实现设定抓取动作
l:电机位置初始化
输入其他命令或超出电机限制范围则会报错

/*该函数主要用来控制机械臂工作*/
#include<Servo.h>
Servo base,fArm,rArm,claw;

#define pi 3.1415926

void reportStatus();
void armDataCmd(char serialCmd);
void servoCmd(char serialCmd,int toPos);
void vel_segmentation(int fromPos,int toPos,Servo arm_servo);
void Arminit();

//建立4个int型变量存储当前电机角度值,设定初始值
int basePos=90;
int rArmPos=90;
int fArmPos=90;
int clawPos=90;

//存储电机极限值
const int baseMin=0;
const int baseMax=180;
const int rArmMin=40;//留一定裕度空间
const int rArmMax=150;//留一定裕度空间
const int fArmMin=20;
const int fArmMax=120;
const int clawMin=40;
const int clawMax=90;

int Dtime = 15;//机械臂运动延迟时间,通过改变该值来控制机械臂运动速度
               //机械臂运动角速度为:π*1000/(180*Dtime) rad/s

void setup() {
  // put your setup code here, to run once:
  base.attach(11);
  delay(200);
  rArm.attach(10);
  delay(200);
  fArm.attach(9);
  delay(200);
  claw.attach(6);
  delay(200);
  Serial.begin(9600);
  Serial.println("-----------------------------------------------");
  Serial.println("Welcome to meArm from K.Fire");
  Serial.println("Control any motor:Input a command like: b135");
  Serial.println("View motors status information:Input 'i'.");
  Serial.println("Fetching function:Input 'g'.");
  Serial.println("Initialize all motors:Input 'l'.");
  Serial.println("-----------------------------------------------");
}

void loop() {
  // put your main code here, to run repeatedly:
  if(Serial.available()>0){
    char serialCmd=Serial.read();//read函数为按字节读取,要注意
    armDataCmd(serialCmd);//实现电机按转角旋转
  }

  base.write(basePos);
  delay(10);
  fArm.write(fArmPos);
  delay(10);
  rArm.write(rArmPos);
  delay(10);
  claw.write(clawPos);
  delay(10);
  //如果设置某个电机角度则产生旋转,否则将保持初值
}



void armDataCmd(char serialCmd){//实现电机按转角旋转的函数
  if(serialCmd == 'b' || serialCmd == 'c' || serialCmd == 'f' || serialCmd == 'r'){
    Serial.print("serialCmd = ");
    Serial.print(serialCmd);
    int servoData = Serial.parseInt();//读取指令中的电机转角
    servoCmd(serialCmd,servoData);
  }
  else{
    switch(serialCmd){
      case 'i': //输出电机状态信息
        reportStatus();
        break;
      case 'l'://电机位置初始化
        Arminit();
        break;
      case 'g'://抓取功能
        GrabSth();
        break;
      default:
        Serial.println();
        Serial.println("【Error】Please Input repeatly!");
        Serial.println();
        break;
    }
  }
}

void servoCmd(char serialCmd,int toPos){
  Serial.println("");
  Serial.print("Command:Servo ");
  Serial.print(serialCmd);
  Serial.print(" to ");
  Serial.print(toPos);
  Serial.print(" at servoVelcity value ");
  Serial.print(1000*pi/(180*Dtime));
  Serial.println(" rad/s.");
  
  int fromPos;//起始位置
  
  switch(serialCmd){
    case 'b':
      if(toPos >= baseMin && toPos <= baseMax){
        fromPos = base.read();
        vel_segmentation(fromPos,toPos,base);
        basePos = toPos;
        Serial.print("Set base servo position value: ");
        Serial.println(toPos);
        Serial.println();
        break;
      }
      else{
        Serial.println("【Warning】Base Servo Position Value Out Of Limit!");
        Serial.println();
        return;
      }
      break;
    case 'r':
      if(toPos >= rArmMin && toPos <= rArmMax){
        fromPos = rArm.read();
        vel_segmentation(fromPos,toPos,rArm);
        rArmPos = toPos;
        Serial.print("Set rArm servo position value: ");
        Serial.println(toPos);
        Serial.println();
        break;
      }
      else{
        Serial.println("【Warning】Base Servo Value Position Out Of Limit!");
        Serial.println();
        return;
      }
      break;
    case 'f':
      if(toPos >= fArmMin && toPos <= fArmMax){
        fromPos = fArm.read();
        vel_segmentation(fromPos,toPos,fArm);
        fArmPos = toPos;
        Serial.print("Set fArm servo position value: ");
        Serial.println(toPos);
        Serial.println();
        break;
      }
      else{
        Serial.println();
        Serial.println("【Warning】Base Servo Value Position Out Of Limit!");
        Serial.println();
        return;
      }
      break;
    case 'c':
      if(toPos >= clawMin && toPos <= clawMax){
        fromPos = claw.read();
        vel_segmentation(fromPos,toPos,claw);
        clawPos = toPos;
        Serial.print("Set claw servo position value: ");
        Serial.println(toPos);
        Serial.println();
        break;
      }
      else{
        Serial.println("【Warning】Base Servo Position Value Out Of Limit!");
        Serial.println();
        return;
      }
      break;
  }
}

void vel_segmentation(int fromPos,int toPos,Servo arm_servo){
  //该函数通过对位置的细分和延时实现电机速度控制
  //这样的控制平均角速度大约为:1°/15ms = 1.16 rad/s
  if(fromPos < toPos){
    for(int i=fromPos;i<=toPos;i++){
        arm_servo.write(i);
        delay(Dtime);
      }
  }
  else{
    for(int i=fromPos;i>=toPos;i--){
        arm_servo.write(i);
        delay(Dtime);
      }
  }
}

void reportStatus(){
  Serial.println();
  Serial.println("---Robot-Arm Status Report---");
  Serial.print("Base Position: ");
  Serial.println(basePos);
  Serial.print("Claw Position: ");
  Serial.println(clawPos);
  Serial.print("rArm Position: ");
  Serial.println(rArmPos);
  Serial.print("fArm Position: ");
  Serial.println(fArmPos);
  Serial.println("-----------------------------");
}

void Arminit(){
  //将电机恢复初始状态
  char ServoArr[4] = {'c','f','r','b'};
  for(int i=0;i<4;i++){
    servoCmd(ServoArr[i],90);
  }
  delay(200);
  Serial.println("Robot Arm has been initized!");
  Serial.println();
}

void GrabSth(){
  //抓取功能
  int GrabSt[4][2] = {
    {'b',135},
    {'r',150},
    {'f',30},
    {'c',40}
  };
  for(int i=0;i<4;i++){
    servoCmd(GrabSt[i][0],GrabSt[i][1]);
  }
}

三、最终控制程序

最终控制程序在基本控制程序的基础上进行了优化,包括实现了手柄模式控制机械臂动作、模式转换、蓝牙远程控制等功能,并对程序的内存进行了合理的分配和优化,流出更多的动态空间,提高了程序的稳定性。

指令格式及说明

b135:将底盘舵机旋转到135°的位置
r60:将大臂舵机旋转到60°的位置
f120:将小臂舵机旋转刀120°的位置
c60:将钳子舵机旋转到60°的位置
i:输出各个电机的转角状态及参数信息
g:实现设定抓取动作
l:电机位置初始化
m:控制模式切换
a:小臂向前旋转
s:底盘向左旋转
d:大臂向前旋转
w:钳子张开
4:小臂向后旋转
5:底盘向右旋转
6:大臂向后旋转
8:钳子闭合
输入其他命令或超出电机限制范围则会报错

/*该函数主要用来控制机械臂工作*/
#include<Servo.h>
Servo base,fArm,rArm,claw;

#define pi 3.1415926

void Introduce();
void armDataCmd(char serialCmd);
void armJoyCmd(char serialCmd);
void servoCmd(char serialCmd,int toPos);
void vel_segmentation(int fromPos,int toPos,Servo arm_servo);
void reportStatus();
void Arminit();
void GrabSth();

//建立4个int型变量存储当前电机角度值,设定初始值
int basePos=90;
int rArmPos=90;
int fArmPos=90;
int clawPos=90;

//存储电机极限值
const int PROGMEM baseMin=0;
const int PROGMEM baseMax=180;
const int PROGMEM rArmMin=40;//留一定裕度空间
const int PROGMEM rArmMax=150;//留一定裕度空间
const int PROGMEM fArmMin=20;
const int PROGMEM fArmMax=120;
const int PROGMEM clawMin=40;
const int PROGMEM clawMax=90;

const int PROGMEM Dtime = 15;//机械臂运动延迟时间,通过改变该值来控制机械臂运动速度
               //机械臂运动角速度为:π*1000/(180*Dtime) rad/s

bool mode = 1;//mode = 1:指令模式;mode = 0:手柄模式
const int PROGMEM moveStep = 3;//按下手柄按键,舵机的位移量

void setup() {
  // put your setup code here, to run once:
  base.attach(11);
  delay(200);
  rArm.attach(10);
  delay(200);
  fArm.attach(9);
  delay(200);
  claw.attach(6);
  delay(200);
  Serial.begin(9600);
  Introduce();

  base.write(90);
  delay(10);
  fArm.write(90);
  delay(10);
  rArm.write(90);
  delay(10);
  claw.write(90);
  delay(10);
}

void loop() {
  // put your main code here, to run repeatedly:
  if(Serial.available()>0){
    char serialCmd=Serial.read();//read函数为按字节读取,要注意!
    if(mode == 1){
      armDataCmd(serialCmd);//实现电机按转角指令旋转
    }
    else{
      armJoyCmd(serialCmd);//手柄控制机械臂
    }
  }
}

void Introduce(){//介绍该程序的操作方法及功能
  Serial.println(F("Welcome to meArm from K.Fire!"));
  Serial.println(F("The rated mode is Instruction Mode."));
  Serial.println(F("-----------------------------------------------"));
  Serial.println(F("Instruction mode!"));
  Serial.println(F("Control any motor:Input a command like: b135"));
  Serial.println(F("-----------------------------------------------"));
  Serial.println(F("Handle mode!"));
  Serial.println(F("fArm forward:  'a'--- fArm backward:  '4'."));
  Serial.println(F("base leftward: 's'--- base rightward: '5'."));
  Serial.println(F("rArm forward:  'd'--- rArm backward:  '6'."));
  Serial.println(F("claw open:     'w'--- claw close:     '8'."));
  Serial.println(F("-----------------------------------------------"));
  Serial.println(F("View motors status information:Input 'i'."));
  Serial.println(F("Fetching function:Input 'g'."));
  Serial.println(F("Initialize all motors:Input 'l'."));
  Serial.println(F("Change working Mode:Input 'm'."));
  Serial.println(F("-----------------------------------------------"));
}

void armDataCmd(char serialCmd){//实现机械臂在指令模式下工作
  if(serialCmd == 'b' || serialCmd == 'c' || serialCmd == 'f' || serialCmd == 'r'){
    Serial.print("serialCmd = ");
    Serial.print(serialCmd);
    int servoData = Serial.parseInt();//读取指令中的电机转角
    servoCmd(serialCmd,servoData);
  }
  else{
    switch(serialCmd){
      case 'i': //输出电机状态信息
        reportStatus();
        break;
      case 'l'://电机位置初始化
        Arminit();
        break;
      case 'g'://抓取功能
        GrabSth();
        break;
      case 'm'://切换电机工作模式
        Serial.println("meArm has been changed into Handle Mode ");
        mode = 0;
        break;
      default:     
        Serial.println();
        Serial.println("【Error】Please Input repeatly!");
        Serial.println();
        break;
    }
  }
}

void armJoyCmd(char serialCmd){//实现机械臂在手柄模式下工作
  int baseJoyPos;
  int rArmJoyPos;
  int fArmJoyPos;
  int clawJoyPos;
  switch(serialCmd){
    case 'a'://小臂正转
      fArmJoyPos = fArm.read() - moveStep;
      servoCmd('f',fArmJoyPos);
      break;
    case 's'://底盘左转
      baseJoyPos = base.read() + moveStep;
      servoCmd('b',baseJoyPos);
      break;
    case 'd'://大臂正转
      rArmJoyPos = rArm.read() + moveStep;
      servoCmd('r',rArmJoyPos);
      break;
    case 'w'://钳子张开
      clawJoyPos = claw.read() - moveStep;
      servoCmd('c',clawJoyPos);
      break;
    case '4'://小臂反转
      fArmJoyPos = fArm.read() + moveStep;
      servoCmd('f',fArmJoyPos);
      break;
    case '5'://底盘右转
      baseJoyPos = base.read() - moveStep;
      servoCmd('b',baseJoyPos);
      break;
    case '6'://大臂反转
      rArmJoyPos = rArm.read() - moveStep;
      servoCmd('r',rArmJoyPos);
      break;
    case '8'://钳子闭合
      clawJoyPos = claw.read() + moveStep;
      servoCmd('c',clawJoyPos);
      break;
    case 'i': //输出电机状态信息
        reportStatus();
        break;
    case 'l'://电机位置初始化
      Arminit();
      break;
    case 'g'://抓取功能
      GrabSth();
      break;
    case 'm'://切换电机工作模式
      Serial.println("meArm has been changed into Instruction Mode");
      mode = 1;
      break;
    default:
      Serial.println();
      Serial.println("【Error】Invalid handle key!");
      Serial.println();
      break;
  }
}

void servoCmd(char serialCmd,int toPos){//电机旋转功能函数
  Serial.println("");
  Serial.print("Command:Servo ");
  Serial.print(serialCmd);
  Serial.print(" to ");
  Serial.print(toPos);
  Serial.print(" at servoVelcity value ");
  Serial.print(1000*pi/(180*Dtime));
  Serial.println(" rad/s.");
  
  int fromPos;//起始位置
  
  switch(serialCmd){
    case 'b':
      if(toPos >= baseMin && toPos <= baseMax){
        fromPos = base.read();
        vel_segmentation(fromPos,toPos,base);
        basePos = toPos;
        Serial.print("Set base servo position value: ");
        Serial.println(toPos);
        Serial.println();
        break;
      }
      else{
        Serial.println("【Warning】Base Servo Position Value Out Of Limit!");
        Serial.println();
        return;
      }
      break;
    case 'r':
      if(toPos >= rArmMin && toPos <= rArmMax){
        fromPos = rArm.read();
        vel_segmentation(fromPos,toPos,rArm);
        rArmPos = toPos;
        Serial.print("Set rArm servo position value: ");
        Serial.println(toPos);
        Serial.println();
        break;
      }
      else{
        Serial.println("【Warning】Base Servo Value Position Out Of Limit!");
        Serial.println();
        return;
      }
      break;
    case 'f':
      if(toPos >= fArmMin && toPos <= fArmMax){
        fromPos = fArm.read();
        vel_segmentation(fromPos,toPos,fArm);
        fArmPos = toPos;
        Serial.print("Set fArm servo position value: ");
        Serial.println(toPos);
        Serial.println();
        break;
      }
      else{
        Serial.println();
        Serial.println("【Warning】Base Servo Value Position Out Of Limit!");
        Serial.println();
        return;
      }
      break;
    case 'c':
      if(toPos >= clawMin && toPos <= clawMax){
        fromPos = claw.read();
        vel_segmentation(fromPos,toPos,claw);
        clawPos = toPos;
        Serial.print("Set claw servo position value: ");
        Serial.println(toPos);
        Serial.println();
        break;
      }
      else{
        Serial.println("【Warning】Base Servo Position Value Out Of Limit!");
        Serial.println();
        return;
      }
      break;
  }
}

void vel_segmentation(int fromPos,int toPos,Servo arm_servo){//速度控制函数
  //该函数通过对位置的细分和延时实现电机速度控制
  //这样的控制平均角速度大约为:1°/15ms = 1.16 rad/s
  if(fromPos < toPos){
    for(int i=fromPos;i<=toPos;i++){
        arm_servo.write(i);
        delay(Dtime);
      }
  }
  else{
    for(int i=fromPos;i>=toPos;i--){
        arm_servo.write(i);
        delay(Dtime);
      }
  }
}

void reportStatus(){//电机状态信息控制函数
  Serial.println();
  Serial.println("---Robot-Arm Status Report---");
  Serial.print("Base Position: ");
  Serial.println(basePos);
  Serial.print("Claw Position: ");
  Serial.println(clawPos);
  Serial.print("rArm Position: ");
  Serial.println(rArmPos);
  Serial.print("fArm Position: ");
  Serial.println(fArmPos);
  Serial.println("-----------------------------");
  Serial.println("Motor Model:Micro Servo 9g-SG90");
  Serial.println("Motor size: 23×12.2×29mm");
  Serial.println("Work temperature:0-60℃");
  Serial.println("Rated voltage: 5V");
  Serial.println("Rated torque: 0.176 N·m");
  Serial.println("-----------------------------");
}

void Arminit(){//电机初始化函数
  //将电机恢复初始状态
  char ServoArr[4] = {'c','f','r','b'};
  for(int i=0;i<4;i++){
    servoCmd(ServoArr[i],90);
  }
  delay(200);
  Serial.println("meArm has been initized!");
  Serial.println();
}

void GrabSth(){//抓取函数
  //抓取功能
  int GrabSt[4][2] = {
    {'b',135},
    {'r',150},
    {'f',30},
    {'c',40}
  };
  for(int i=0;i<4;i++){
    servoCmd(GrabSt[i][0],GrabSt[i][1]);
  }
}

蓝牙控制:使用HC-06蓝牙模块,将其RX、TX引脚分别与arduino的TX、RX引脚相连,使用相应的软件即(如:Arduino bluetooth controller.apk)可实现控制。

所有程序资源大家可以免费下载


总结

目前实现的功能都很简单,并且是基于Arduino开发的程序,况且对于Arduino我认为也没有特别深入的理解,有很多功能尚未开发使用,现在我正在开发另一个项目-差速小车,想完成激光雷达SLAM建图、路径规划及智能循迹,完成这之后应该会再捞起机械臂,进行机械臂的再升级改良,比如实现机械臂抓取的正解、逆解问题,更换舵机进行控制算法的优化、以及机械臂和移动小车底盘的协作等功能,继续加油。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【meArm机械臂】第二篇·Arduino控制程序 的相关文章

  • 【Ubuntu20.04】ROS的安装与配置,话题通信、服务通信的编程实践验证

    Ubuntu20 04下ROS的安装与配置 xff0c 话题通信 服务通信的编程实践验证 一 ROS的安装1 1设置软件源1 2安装ROS noetic1 2 1添加 sources list1 2 2设置keys1 2 3更新系统软件源1
  • 使用scp转移站点到新的服务器

    使用scp将一个Linux系统中的文件或文件夹复制到另一台Linux服务器上 复制文件或文件夹 xff08 目录 xff09 命令 xff1a 一 复制文件 xff1a xff08 1 xff09 将本地文件拷贝到远程 scp 文件名 用户
  • Wrapper 子句构造器

    Wrapper的两个子类 1 QueryWrapper lt T gt 作为where条件子句的构造器 2 UpdateWrapper lt T gt 作为set子句的构造器 IPage 分页器接口 1 Page 类 不同数据库的分页的SQ
  • MOBILEVITV3: MOBILE-FRIENDLY VISION TRANS- FORMER WITH SIMPLE AND EFFECTIVE FUSION OF LOCAL, GLOBAL

    paper链接 https arxiv org abs 2209 15159 code链接 MOBILEVITV3 MOBILE FRIENDLY VISION TRANS FORMER WITH SIMPLE AND EFFECTIVE
  • 位置型PID的实现——基于直线一级倒立摆

    倒立摆的实验是在小半年前的课程实验中遇到的 xff0c 由于比较感兴趣 xff0c 就多花了些时间研究了一下 xff0c 实验设备是前海格致便携倒立摆 xff0c 编写语言是C语言 xff0c 如果你需要使用其他语言 xff0c 我相信在理
  • 第7章 HBase操作

    文章目录 一 xff1a 判断题二 xff1a 单选题三 xff1a 主观题1 xff1a 创建学生表scores xff0c 列族为grade 年级 course 课程 xff0c 学生姓名name作为行健的代码 2 xff1a 查看创建
  • Python/Pytorch常用函数大汇总(持续更新中)

    python装饰器 def dec1 func print 34 1111 34 def one print 34 2222 34 func print 34 3333 34 return one def dec2 func print 3
  • 将uc/OS其移植到stm32并完成相关任务

    目录 一 uc OS的介绍 1 概述 2 工作原理 3 主要特点 二 创建cubemx项目 1 选择stm32f103c8 2 配置RCC 编辑 3 配置SYS 4 生成项目 三 移植和keil5相关操作 1 进入官网下载 xff1a ht
  • 匿名飞控TI版_PID部分,串级PID,微分先行,前馈控制

    文章目录 PID介绍有趣的故事控制模型位置式PID和增量式PID位置式PID增量式PID 串级PID前馈控制微分先行匿名代码分析 PID介绍 PID介绍 有趣的故事 PID的故事 space space space space space
  • c#委托的定义和使用

    什么是委托 xff1f 当你需要将方法当成一个参数传递的时候就需要使用委托 xff0c 委托是一个类型 xff0c 可以赋值一个方法的引用 具体怎么使用下面就简单展示一下 1 定义委托 delegate void MyDelegate in
  • ssh登录出现 “WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!”解决办法

    问题场景 xff1a 第一次ssh板子成功登录后 xff0c 换了另外一块同样型号的开发板 xff0c 重新ssh远程登录 xff0c 出现了WARNING REMOTE HOST IDENTIFICATION HAS CHANGED 问题
  • 多线程及网络编程

    目录 实验目的及要求 一 实验原理 xff1a 二 操作步骤 xff1a 三 实验数据 1 模拟火车站4个窗口同时卖50张票 2 使用UDP协议实现用户信息的发送和接收功能 3 运用TCP协议实现向服务器上传文件 实验结果及分析 个人简介
  • 阿里云在线扩容磁盘,最简化,但不一定适用你的ECS版本

    在扩展系统盘扩展分区和文件系统前 xff0c 请提前完成以下工作 已创建快照备份数据 为防止操作失误导致数据丢失 xff0c 建议您操作前使用快照备份数据 若尚未创建快照 xff0c 请参见创建快照 已扩容云盘 若尚未扩容 xff0c 请参
  • AD学习笔记(二)原理图库以及原理图绘制

    文章目录 AD学习笔记第二讲 原理图库以及原理图绘制一 认识原理图二 原理图库绘制三 原理图绘制1 原理图纸的操作2 原理图库的调用放置3 导线及网络标识的添加4 原理图可读性优化处理5 原理图统一编号设置6 PCB封装名称的统一添加与管理
  • C工程与寄存器封装

    目录 一 C语言工程简介 二 启动代码分析 三 C语言实现LED 四 寄存器的封装方式 五 寄存器操作的标准化 六 流水灯 一 C语言工程简介 先将工程模板解压 include里是 h文件 src里是 c文件 start里面是 s启动文件
  • Python第三章函数

    函数 文章目录 函数一 函数基础1 参数2 拆分参数列表3 参数传递位置传递地址传递传对象引用 4 函数返回值5 变量的作用域局部变量全局变量nonlocal关键字 7 包8 猴子补丁9 python标准库的应用1 random模块2 ti
  • 无显示器怎么玩树莓派

    无显示器怎么玩树莓派 文章目录 无显示器怎么玩树莓派 前言一 给树莓派烧系统二 设置WiFi及ssh端口三 远程连接四 注意事项 前言 很多时候我们在使用树莓派的时候身边都没有显示器 xff0c 关于这个问题 xff0c 我也十分苦恼 xf
  • ROS智能车定位导航仿真(Gazebo搭建赛道)

    ROS智能车定位导航仿真 xff08 Gazebo搭建赛道 xff09 前言一 ROS仿真功能包下载二 安装运行所需的插件三 racecar功能包编译四 测试程序运行五 运行功能包赛道六 注意事项 前言 Ubuntu版本 xff1a 18
  • 阿木实验室PX4开发课程整理

    1 1 xff1a alt 43 ctrl 43 t 打开终端 cd Desktop 进入到桌面目录 cd 返回上次访问目录 cd 返回上一目录 gedit circular cpp 进入某文件 roscd px4 control 进入文件
  • Java并发编程—CompletableFuture的异步执行案例

    在博主前几篇博客中 xff0c https blog csdn net qq 52545155 article details 128167519 spm 61 1001 2014 3001 5501 xff0c 给大家分享了关于多线程中异

随机推荐

  • 手写rtos的第一天

    唉 xff0c 不自不觉已经大三了啊 xff0c 大二的智能车生涯已经结束了 xff0c 不得不说 xff0c 省二是我不太能接受的 结果 xff0c 虽然嘴上说着没啥 xff0c 真正面对全省排名的时候 xff0c 内心的寂寥真的难以言表
  • FreeRTOS任务(动态)创建与删除(一)

    FreeRTOS学习总结 文章目录 前言一 浅浅了解二 创建任务1 动态任务创建2 动态实践 总结 前言 听朋友说 xff0c FreeRTOS很好用 xff0c 就在无聊的上网课期间浅学一下 提示 xff1a 以下是本篇文章正文内容 xf
  • FreeRTOS操作系统队列及队列API函数(五)

    FreeRTOS学习总结 文章目录 前言一 队列功能1 数据存储2 多任务访问3 出队阻塞4 入队阻塞 二 队列操作过程图示1 创建队列2 向队列发送第一个消息3 向队列发送第二个消息4 从队列中读取消息 二 API函数1 队列创建函数2
  • php导出word文件,打开损坏或者乱码

    下载Word文件 fileinfo 61 pathinfo fullname ob end clean header 39 Content type application x 39 fileinfo 39 extension 39 hea
  • FreeRTOS操作系统优先级翻转问题(八)

    FreeRTOS总结 文章目录 前言一 浅浅了解优先级翻转二 模拟 优先级翻转实验1 代码 总结 前言 在使用二值信号量的时候会遇到很常见的一个问题 优先级翻转 xff0c 优先级翻转在可剥夺 内核中是非常常见的 xff0c 在实时系统中不
  • 伽马分布,指数分布,卡方分布三者关系

    1 伽马分布是一个连续概率分布 xff0c 具有两个参数 alpha 和 lambda xff0c 记为
  • 数据结构 马踏棋盘 栈应用 C++

    include lt iostream gt 包含其它头文件 using namespace std const int StackInitSize 61 10 const int StackInc 61 10 typedef int SE
  • STM32智能小车------红外遥控

    文章目录 一 原理讲解1 实物图2 工作原理 xff1a 3 接线 xff1a 二 软件驱动代码1 驱动函数2 获取键值 总结最终效果 大家好哇 xff01 我是小光 xff0c 嵌入式爱好者 xff0c 一个想要成为系统架构师的普通大学生
  • UCOS学习(一)——前后台系统、RTOS系统

    大家好哇 xff01 我是小光 xff0c 嵌入式爱好者 xff0c 一个想要成为系统架构师的大二学生 最近开始学习UCOS操作系统 xff0c 后面会更新一些关于UCOS学习笔记 今天了解了UCOS操作系统 xff0c 总结一下知识点 感
  • UCOS学习(二)——UCOS-II、UCOS-III移植到STM32F103

    大家好哇 xff01 我是小光 xff0c 嵌入式爱好者 xff0c 一个想要成为系统架构师的大二学生 最近开始学习UCOS操作系统 xff0c 后面会更新一些关于UCOS学习笔记 今天学习了如何将UCOS II和UCOS III移植到ST
  • UCOS学习(三)——任务管理基础

    大家好哇 xff01 我是小光 xff0c 嵌入式爱好者 xff0c 一个想要成为系统架构师的大二学生 最近开始学习UCOS操作系统 xff0c 后面会更新一些关于UCOS学习笔记 今天学习了任务管理基础知识 感谢你的阅读 xff0c 不对
  • UCOS学习(七)——信号量详解

    信号量 信号量简介信号量保护共享资源举个栗子 xff1a 如果不使用信号量信号量解决公共资源问题创建信号量 xff1a 信号量实现任务同步总结 信号量简介 信号量像是一种上锁机制 xff0c 代码必须获得对应的钥匙才能继续执行 xff0c
  • Altium Designer(AD)的简易使用

    一 绘制原理图 原理图库 首先来说明原理图的概念 根据百度百科 xff0c 原理图 xff0c 顾名思义就是表示电路板上各器件之间连接原理的图表 也就是表示芯片上的引脚连接什么元件 xff0c 各个元件谁和谁相连 xff0c 电源电压的大小
  • STM32CubeIDE---HAL库PWM使用速记

    一 如何计算 理论分析 xff1a HAL库函数之呼吸灯 PWM波 简书 jianshu com 预分频系数 PSC 自动重装载值 ARR 捕获 比较寄存器值 CCR 频率计算 xff1a 定时器频率 PSC 43 1 ARR 43 1 占
  • mac常用命令

    mac清除电脑DNS缓存 sudo dscacheutil flushcache
  • IMU初介绍及里程计相关补充

    IMU原理 xff1a 以牛顿力学定律为基础 xff0c 通过测量载体在惯性参考系的加速度 xff0c 将它对时间进行积分 xff0c 且把它变换到导航坐标系中 xff0c 就能够得到在导航坐标系中的速度 偏航角和位置等信息 IMU xff
  • C语言变量的定义与声明,为什么全局变量不能赋值

    文章目录 一 对C语言程序的一些补充二 定义域声明2 1 什么是变量2 2 如何定义变量2 3 为什么要定义变量2 4 定义变量的本质2 5 变量声明的本质2 6 定义和声明的区别 三 全局变量无法赋值 一 对C语言程序的一些补充 对于一个
  • 野火PID上位机通信移植

    野火PID上位机通信移植 一 简介 在调试pid参数的时候 xff0c 需要用到上位机 xff0c 这里选用 野火多功能调试助手 使用调试助手 xff0c 需要下位机与上位机之间的通信协议 xff0c 下载野火关于电机的相关例程 xff0c
  • 实验报告数字图像的基本操作

    一 实验目的 了解Matlab的基本功能及操作方法练习图像读写和显示函数的使用方法掌握如何利用MATLAB来获取图像的大小 颜色 高度 宽度等等相关信息熟悉常用的图像文件格式与格式转换 xff1b 二 实验环境 PC计算机MatLab软件
  • 【meArm机械臂】第二篇·Arduino控制程序

    系列文章目录 meArm机械臂 第一篇 结构设计及搭建 meArm机械臂 第二篇 Arduino控制程序 文章目录 系列文章目录前言一 测试程序1 单个电机测试程序2 四舵机控制测试程序3 极限位置测量 二 基本控制程序三 最终控制程序总结