Ubuntu 22.04下以SOEM为EtherCAT主站的驱动电机例子

这篇具有很好参考价值的文章主要介绍了Ubuntu 22.04下以SOEM为EtherCAT主站的驱动电机例子。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言

这篇文章是笔者的第一篇文章,笔者作为一个机器人从业者,经常要接触到EtherCAT与ROS等相关内容。目前市面上有的开源EtherCAT系统有Igh以及SOEM两种,Igh在多年前已经停止维护,而截至日前SOEM依然维持更新,且SOEM已经集成到ROS生态中,故笔者选择SOEM进行研究。

苦于网上资料较少,笔者在学习摸索期间遇到大大小小的坑,浪费了不少时间。如今分享一下自己的一个例程,希望大家也能尽快掌握SOEM的使用。

开发环境

操作系统:Ubuntu22.04
系统内核:Linux 5.15.0-1022-realtime
注:Ubuntu在22.04版本已经提供官方的实时补丁,不需要自己编译实时内核,其使用的是preempt-rt补丁,实时性与自己打的补丁一样。可参考:Real-time Ubuntu 22.04 LTS Beta – Now Available

例程

介绍

该例程的作用为控制伺服电机,通过SOEM与电机驱动器进行通讯。

代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#define __USE_GNU
#include <pthread.h>
#include <math.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h> //PISOX中定义的标准接口

#include "ethercat.h"

#define NSEC_PER_SEC 1000000000
#define EC_TIMEOUTMON 500

#define EEP_MAN_SYNAPTICON (0x000022d2)
#define EEP_ID_SYNAPTICON (0x00000201)

struct sched_param schedp;
char IOmap[4096];
pthread_t thread1, thread2;
uint64_t diff, maxt, avg, cycle;
struct timeval t1, t2;
int dorun = 0;
int64 toff = 0;
int expectedWKC;
boolean needlf;
volatile int wkc;
boolean inOP;
uint8 currentgroup = 0;


enum {
   STATE_RESET,
   STATE_INIT,
   STATE_PREREADY,
   STATE_READY,
   STATE_ENABLE,
   STATE_DISABLE
}

int state = STATE_RESET;

typedef struct PACKED
{
   uint16_t Controlword;
   int16_t TargetTor;
   int32_t TargetPos;
   int32_t TargetVel;
   uint8_t ModeOp;
   int16_t TorOff;
} Drive_Outputs;

typedef struct PACKED
{
   uint16_t Statusword;
   int32_t ActualPos;
   int32_t ActualVel;
   int16_t ActualTor;
   uint8_t ModeOp;
   int32_t SecPos;
} Drive_Inputs;

static int drive_write8(uint16 slave, uint16 index, uint8 subindex, uint8 value)
{
   int wkc;

   wkc = ec_SDOwrite(slave, index, subindex, FALSE, sizeof(value), &value, EC_TIMEOUTRXM);

   return wkc;
}

static int drive_write16(uint16 slave, uint16 index, uint8 subindex, uint16 value)
{
   int wkc;

   wkc = ec_SDOwrite(slave, index, subindex, FALSE, sizeof(value), &value, EC_TIMEOUTRXM);

   return wkc;
}

static int drive_write32(uint16 slave, uint16 index, uint8 subindex, int32 value)
{
   int wkc;

   wkc = ec_SDOwrite(slave, index, subindex, FALSE, sizeof(value), &value, EC_TIMEOUTRXM);

   return wkc;
}

// 该函数用于设置PDO映射表
int drive_setup(uint16 slave)
{
   int wkc = 0;

   printf("Drive setup\n");

   wkc += drive_write16(slave, 0x1C12, 0, 0);
   wkc += drive_write16(slave, 0x1C13, 0, 0);

   wkc += drive_write16(slave, 0x1A00, 0, 0);
   wkc += drive_write32(slave, 0x1A00, 1, 0x60410010); // Statusword
   wkc += drive_write32(slave, 0x1A00, 2, 0x60640020); // Position actual value
   wkc += drive_write32(slave, 0x1A00, 3, 0x606C0020); // Velocity actual value
   wkc += drive_write32(slave, 0x1A00, 4, 0x60770010); // Torque actual value
   wkc += drive_write32(slave, 0x1A00, 5, 0x60610008); // Modes of operation display
   wkc += drive_write32(slave, 0x1A00, 6, 0x230A0020); // 2nd Pos
   wkc += drive_write8(slave, 0x1A00, 0, 6);

   wkc += drive_write8(slave, 0x1600, 0, 0);
   wkc += drive_write32(slave, 0x1600, 1, 0x60400010); // Controlword
   wkc += drive_write32(slave, 0x1600, 2, 0x60710010); // Target torque
   wkc += drive_write32(slave, 0x1600, 3, 0x607A0020); // Target position
   wkc += drive_write32(slave, 0x1600, 4, 0x60FF0020); // Target velocity
   wkc += drive_write32(slave, 0x1600, 5, 0x60600008); // Modes of operation display
   wkc += drive_write32(slave, 0x1600, 6, 0x60B20010); // Torque offset
   wkc += drive_write8(slave, 0x1600, 0, 6);

   wkc += drive_write16(slave, 0x1C12, 1, 0x1600);
   wkc += drive_write8(slave, 0x1C12, 0, 1);

   wkc += drive_write16(slave, 0x1C13, 1, 0x1A00);
   wkc += drive_write8(slave, 0x1C13, 0, 1);

   strncpy(ec_slave[slave].name, "Drive", EC_MAXNAME);

   if (wkc != 22)
   {
      printf("Drive %d setup failed\nwkc: %d\n", slave, wkc);
      return -1;
   }
   else
      printf("Drive %d setup succeed.\n", slave);

   return 0;
}

/* add ns to timespec */
void add_timespec(struct timespec *ts, int64 addtime)
{
   int64 sec, nsec;

   nsec = addtime % NSEC_PER_SEC;
   sec = (addtime - nsec) / NSEC_PER_SEC;
   ts->tv_sec += sec;
   ts->tv_nsec += nsec;
   if (ts->tv_nsec > NSEC_PER_SEC)
   {
      nsec = ts->tv_nsec % NSEC_PER_SEC;
      ts->tv_sec += (ts->tv_nsec - nsec) / NSEC_PER_SEC;
      ts->tv_nsec = nsec;
   }
}

/* PI calculation to get linux time synced to DC time */
void ec_sync(int64 reftime, int64 cycletime, int64 *offsettime)
{
   static int64 integral = 0;
   int64 delta;
   /* set linux sync point 50us later than DC sync, just as example */
   delta = (reftime - 50000) % cycletime;
   if (delta > (cycletime / 2))
   {
      delta = delta - cycletime;
   }
   if (delta > 0)
   {
      integral++;
   }
   if (delta < 0)
   {
      integral--;
   }
   *offsettime = -(delta / 100) - (integral / 20);
}

static inline int64_t calcdiff_ns(struct timespec t1, struct timespec t2)
{
   int64_t tdiff;
   tdiff = NSEC_PER_SEC * (int64_t)((int)t1.tv_sec - (int)t2.tv_sec);
   tdiff += ((int)t1.tv_nsec - (int)t2.tv_nsec);
   return tdiff;
}

static int latency_target_fd = -1;
static int32_t latency_target_value = 0;

/* 消除系统时钟偏移函数,取自cyclic_test */
static void set_latency_target(void)
{
   struct stat s;
   int ret;

   if (stat("/dev/cpu_dma_latency", &s) == 0)
   {
      latency_target_fd = open("/dev/cpu_dma_latency", O_RDWR);
      if (latency_target_fd == -1)
         return;
      ret = write(latency_target_fd, &latency_target_value, 4);
      if (ret == 0)
      {
         printf("# error setting cpu_dma_latency to %d!: %s\n", latency_target_value, strerror(errno));
         close(latency_target_fd);
         return;
      }
      printf("# /dev/cpu_dma_latency set to %dus\n", latency_target_value);
   }
}

void test_driver(char *ifname, int mode)
{
   int cnt, i, j ;
   Drive_Inputs *iptr;
   Drive_Outputs *optr;
   struct sched_param schedp;
   cpu_set_t mask;
   pthread_t thread;
   int ht;
   int chk = 2000;
   int64 cycletime;
   struct timespec ts, tnow;

   CPU_ZERO(&mask);
   CPU_SET(2, &mask);
   thread = pthread_self();
   pthread_setaffinity_np(thread, sizeof(mask), &mask);

   memset(&schedp, 0, sizeof(schedp));
   schedp.sched_priority = 99; /* 设置优先级为99,即RT */
   sched_setscheduler(0, SCHED_FIFO, &schedp);

   printf("Starting Redundant test\n");

   /* initialise SOEM, bind socket to ifname */
   if (ec_init(ifname))
   {
      printf("ec_init on %s succeeded.\n", ifname);
      /* find and auto-config slaves */
      if (ec_config_init(FALSE) > 0)
      {
         printf("%d slaves found and configured.\n", ec_slavecount);
         /* wait for all slaves to reach SAFE_OP state */

         int slave_ix;
         for (slave_ix = 1; slave_ix <= ec_slavecount; slave_ix++)
         {
            ec_slavet *slave = &ec_slave[slave_ix];
            slave->PO2SOconfig = drive_setup;
         }

         /* configure DC options for every DC capable slave found in the list */
         ec_config_map(&IOmap); // 此处调用drive_setup函数,进行PDO映射表设置
         ec_configdc(); // 设置同步时钟,该函数必须在设置pdo映射之后;

         // setup dc for devices
         for (slave_ix = 1; slave_ix <= ec_slavecount; slave_ix++)
         {
            ec_dcsync0(slave_ix, TRUE, 4000000U, 20000U);
            // ec_dcsync01(slave_ix, TRUE, 4000000U, 8000000U, 20000U);
         }

         printf("Slaves mapped, state to SAFE_OP.\n");
         ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE);

         /* read indevidual slave state and store in ec_slave[] */
         ec_readstate();
         for (cnt = 1; cnt <= ec_slavecount; cnt++)
         {
            printf("Slave:%d Name:%s Output size:%3dbits Input size:%3dbits State:%2d delay:%d.%d\n",
                   cnt, ec_slave[cnt].name, ec_slave[cnt].Obits, ec_slave[cnt].Ibits,
                   ec_slave[cnt].state, (int)ec_slave[cnt].pdelay, ec_slave[cnt].hasdc);
         }
         expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC;
         printf("Calculated workcounter %d\n", expectedWKC);

         printf("Request operational state for all slaves\n");
         /* activate cyclic process data */
         /* wait for all slaves to reach OP state */
         ec_slave[0].state = EC_STATE_OPERATIONAL;
         /* request OP state for all slaves */
         ec_writestate(0);

         clock_gettime(CLOCK_MONOTONIC, &ts);
         ht = (ts.tv_nsec / 1000000) + 1; /* round to nearest ms */
         ts.tv_nsec = ht * 1000000;
         cycletime = 4000 * 1000; /* cycletime in ns */

         /* 对PDO进行初始化 */
         for (i = 0; i < ec_slavecount; i++)
         {
            optr = (Drive_Outputs *)ec_slave[i + 1].outputs;
            if(optr == NULL)
            {
               printf("optr is NULL.\n");
            }
            optr->Controlword = 0;
            optr->TargetPos = 0;
            optr->ModeOp = 0;
            optr->TargetTor = 0;
            optr->TargetVel = 0;
            optr->TorOff = 0;
         }

         do
         {
            /* wait to cycle start */
            clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL);
            if (ec_slave[0].hasdc)
            {
               /* calulate toff to get linux time and DC synced */
               ec_sync(ec_DCtime, cycletime, &toff);
            }
            wkc = ec_receive_processdata(EC_TIMEOUTRET);
            ec_send_processdata();
            add_timespec(&ts, cycletime + toff);
         } while (chk-- && (wkc != expectedWKC)); 
         /* 此处与SOEM官方例程不一样,因为ec_statecheck函数消耗的时间较多,有可能超过循环周期 */

         if (wkc == expectedWKC)
         {
            printf("Operational state reached for all slaves.\n");
            inOP = TRUE;
            cnt = 0;
            while (cnt<10)
            {
               /* 计算下一周期唤醒时间 */
               add_timespec(&ts, cycletime + toff);
               /* wait to cycle start */
               clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL);
               clock_gettime(CLOCK_MONOTONIC, &tnow);
               if (ec_slave[0].hasdc)
               {
                  /* calulate toff to get linux time and DC synced */
                  ec_sync(ec_DCtime, cycletime, &toff);
               }
               wkc = ec_receive_processdata(EC_TIMEOUTRET);
               diff = calcdiff_ns(tnow, ts);

               switch (state)
               {
               case STATE_RESET: /* 对驱动器清除故障 */
                  for (i = 0; i < ec_slavecount; i++)
                  {
                     optr = (Drive_Outputs *)ec_slave[i + 1].outputs;
                     optr->Controlword = 128;
                  }
                  state = 0;
                  break;
               case STATE_INIT /* 初始化驱动器 */:
                  for (i = 0; i < ec_slavecount; i++)
                  {
                     optr = (Drive_Outputs *)ec_slave[i + 1].outputs;
                     iptr = (Drive_Inputs *)ec_slave[i + 1].inputs;
                     optr->Controlword = 0;
                     optr->TargetPos = iptr->ActualPos;
                  }
                  state = STATE_PREREADY;
                  break;
               case STATE_PREREADY:
                  for (i = 0; i < ec_slavecount; i++)
                  {
                     optr = (Drive_Outputs *)ec_slave[i + 1].outputs;
                     optr->Controlword = 6;
                  }
                  state = STATE_READY;
                  break;
               case STATE_READY /* 系统转为准备使能状态 */:
                  for (i = 0; i < ec_slavecount; i++)
                  {
                     optr = (Drive_Outputs *)ec_slave[i + 1].outputs;
                     optr->Controlword = 7;
                     optr->ModeOp = 8;
                  }
                  state = STATE_ENABLE;
                  break;
               case STATE_ENABLE /* 驱动器使能 */:
                  for (i = 0; i < ec_slavecount; i++)
                  {
                     optr = (Drive_Outputs *)ec_slave[i + 1].outputs;
                     optr->Controlword = 15;
                  }
                  break;
               case STATE_DISABLE:
               /* 使电机失能并在10个循环之后退出循环 */
                  for (i = 0; i < ec_slavecount; i++)
                  {
                     optr = (Drive_Outputs *)ec_slave[i + 1].outputs;
                     optr->ModeOp = 0;
                     optr->TargetVel = 0;
                     optr->Controlword = 6;
                  }
                  cnt ++;
                  break;
               default:
                  break;
               }
               ec_send_processdata();
               cycle++;

               avg += diff;
               if (diff > maxt)
                  maxt = diff;

               for (j = 0; j < 1; j++)
               {
                  iptr = (Drive_Inputs *)ec_slave[j + 1].inputs;
                  optr = (Drive_Outputs *)ec_slave[j + 1].outputs;
                  printf("  %d: CW: %d, status: %d, pos: %d", j + 1, optr->Controlword, iptr->Statusword, iptr->ActualPos);
               }
               printf(", MaxLatency: %lu, avg: %lu    \r", maxt, avg / cycle);
               fflush(stdout);
            }
            dorun = 0;
         }
         else /* ECAT进入OP失败 */
         {
            printf("Not all slaves reached operational state.\n");
            ec_readstate();
            for (i = 1; i <= ec_slavecount; i++)
            {
               if (ec_slave[i].state != EC_STATE_OPERATIONAL)
               {
                  printf("Slave %d State=0x%2.2x StatusCode=0x%4.4x : %s\n",
                         i, ec_slave[i].state, ec_slave[i].ALstatuscode, ec_ALstatuscode2string(ec_slave[i].ALstatuscode));
               }
            }
         }
         /* 断开ECAT通讯 */
         printf("\nRequest safe operational state for all slaves\n");
         ec_slave[0].state = EC_STATE_SAFE_OP;
         /* request SAFE_OP state for all slaves */
         ec_writestate(0);
         ec_slave[0].state = EC_STATE_PRE_OP;
         ec_writestate(0);
         ec_slave[0].state = EC_STATE_INIT;
         ec_writestate(0);
         ec_readstate();
         if (ec_statecheck(0, EC_STATE_SAFE_OP, 1000) == EC_STATE_INIT)
         {
            printf("ECAT changed into state init\n");
         }
      }
      else
      {
         printf("No slaves found!\n");
      }
      printf("End driver test, close socket\n");
      /* stop SOEM, close socket */
      ec_close();
   }
   else
   {
      printf("No socket connection on %s\nExcecute as root\n", ifname);
   }
}

// 检测键盘输入,如检测到esc即关闭SOEM退出程序
OSAL_THREAD_FUNC scanKeyboard()
{
   int in;
   // int i;
   // Drive_Outputs *optr;
   struct sched_param schedp;
   cpu_set_t mask;
   pthread_t thread;
   struct termios new_settings;
   struct termios stored_settings;

   CPU_ZERO(&mask);
   CPU_SET(2, &mask);
   thread = pthread_self();
   pthread_setaffinity_np(thread, sizeof(mask), &mask);
   memset(&schedp, 0, sizeof(schedp));
   schedp.sched_priority = 20;
   sched_setscheduler(0, SCHED_FIFO, &schedp);

   tcgetattr(0, &stored_settings);
   new_settings = stored_settings;
   new_settings.c_lflag &= (~ICANON); //屏蔽整行缓存
   new_settings.c_cc[VTIME] = 0;

   /*这个函数调用把当前终端接口变量的值写入termios_p参数指向的结构。
   如果这些值其后被修改了,你可以通过调用函数tcsetattr来重新配置
   调用tcgetattr初始化一个终端对应的termios结构
   int tcgetattr(int fd, struct termios *termios_p);*/
   tcgetattr(0, &stored_settings);
   new_settings.c_cc[VMIN] = 1;

   /*int tcsetattr(int fd , int actions , const struct termios *termios_h)
   参数actions控制修改方式,共有三种修改方式,如下所示。
   1.TCSANOW:立刻对值进行修改
   2.TCSADRAIN:等当前的输出完成后再对值进行修改。
   3.TCSAFLUSH:等当前的输出完成之后,再对值进行修改,但丢弃还未从read调用返回的当前的可用的任何输入。*/
   tcsetattr(0, TCSANOW, &new_settings);
   in = getchar();
   tcsetattr(0, TCSANOW, &stored_settings);
   while (1)
   {
      if (in == 27)
      {
         state = STATE_DISABLE;
         printf("the keyboard input is: \n");
         putchar(in);
         break;
      }
      osal_usleep(10000); //间隔10ms循环一次;
   }
}

OSAL_THREAD_FUNC ecatcheck(void *ptr)
{
   int slave;
   (void)ptr; /* Not used */
   struct sched_param schedp;
   cpu_set_t mask;
   pthread_t thread;
   time_t terr;

   /* 设定线程优先级为20 */
   CPU_ZERO(&mask);
   CPU_SET(2, &mask);
   thread = pthread_self();
   pthread_setaffinity_np(thread, sizeof(mask), &mask);

   memset(&schedp, 0, sizeof(schedp));
   schedp.sched_priority = 21;
   sched_setscheduler(0, SCHED_FIFO, &schedp);

   while (1)
   {
      if (inOP && ((wkc < expectedWKC) || ec_group[currentgroup].docheckstate))
      {
         time(&terr);
         printf("wkc: %d, expwkc: %d, docheckstate: %d, error time: %s\n", wkc, expectedWKC, ec_group[0].docheckstate, ctime(&terr));
         if (needlf)
         {
            needlf = FALSE;
            printf("\n");
         }
         /* one ore more slaves are not responding */
         ec_group[currentgroup].docheckstate = FALSE;
         ec_readstate();
         for (slave = 1; slave <= ec_slavecount; slave++)
         {
            if ((ec_slave[slave].group == currentgroup) && (ec_slave[slave].state != EC_STATE_OPERATIONAL))
            {
               ec_group[currentgroup].docheckstate = TRUE;
               if (ec_slave[slave].state == (EC_STATE_SAFE_OP + EC_STATE_ERROR))
               {
                  printf("ERROR : slave %d is in SAFE_OP + ERROR, attempting ack.\n", slave);
                  ec_slave[slave].state = (EC_STATE_SAFE_OP + EC_STATE_ACK);
                  ec_writestate(slave);
               }
               else if (ec_slave[slave].state == EC_STATE_SAFE_OP)
               {
                  printf("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n", slave);
                  ec_slave[slave].state = EC_STATE_OPERATIONAL;
                  ec_writestate(slave);
               }
               else if (ec_slave[slave].state > EC_STATE_NONE)
               {
                  if (ec_reconfig_slave(slave, EC_TIMEOUTMON))
                  {
                     ec_slave[slave].islost = FALSE;
                     printf("MESSAGE : slave %d reconfigured\n", slave);
                  }
               }
               else if (!ec_slave[slave].islost)
               {
                  /* re-check state */
                  ec_statecheck(slave, EC_STATE_OPERATIONAL, EC_TIMEOUTRET);
                  if (ec_slave[slave].state == EC_STATE_NONE)
                  {
                     ec_slave[slave].islost = TRUE;
                     printf("ERROR : slave %d lost\n", slave);
                  }
               }
            }
            if (ec_slave[slave].islost)
            {
               if (ec_slave[slave].state == EC_STATE_NONE)
               {
                  if (ec_recover_slave(slave, EC_TIMEOUTMON))
                  {
                     ec_slave[slave].islost = FALSE;
                     printf("MESSAGE : slave %d recovered\n", slave);
                  }
               }
               else
               {
                  ec_slave[slave].islost = FALSE;
                  printf("MESSAGE : slave %d found\n", slave);
               }
            }
         }
         if (!ec_group[currentgroup].docheckstate)
            printf("OK : all slaves resumed OPERATIONAL.\n");
      }
      osal_usleep(10000);
   }
}

#define stack64k (64 * 1024)

int main(int argc, char *argv[])
{
   int mode;

   printf("SOEM (Simple Open EtherCAT Master)\nRedundancy test\n");
   if (argc > 1)
   {
      dorun = 0;

      set_latency_target(); // 消除系统时钟偏移

      /* create thread to handle slave error handling in OP */
      osal_thread_create(&thread2, stack64k * 4, &ecatcheck, NULL);
      osal_thread_create(&thread1, stack64k * 4, &scanKeyboard, NULL);

      /* start acyclic part */
      test_driver(argv[1]);
   }
   else
   {
      printf("Usage: red_test ifname1 Mode_of_operation\nifname = eth0 for example\n");
   }

   printf("End program\n");

   return (0);
}

解析

本代码在SOEM官方示例代码red_test的基础上加入了优先级实现,取消系统时间偏移,PDO映射表实现,PDO、SDO传输等功能。
需要注意的是,其中在ECAT进入OP状态的时候使用了wkc与expectedWKC的相等条件进行判断,因为ec_statecheck函数耗时过长,有可能导致错误,同样ec_readstate函数消耗时间也是很长,还会对其他线程形成阻塞,注意不要添加在循环当中。

结语

以上为笔者分享的关于SOEM的驱动电机的一个小例程,希望可以对感兴趣的读者产生启发,也欢迎大家前来交流沟通。文章来源地址https://www.toymoban.com/news/detail-522860.html

到了这里,关于Ubuntu 22.04下以SOEM为EtherCAT主站的驱动电机例子的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ubuntu22.04安装显卡驱动

    1、禁用 nouveau 在文本最后添加: 点击保存后更新必备环境源  更新后输入该命令验证 无输出即代表禁用成功(ps:不行可以重启电脑) 2、secure boot问题 法一:直接禁用链接1、链接2(安装前禁用) 法二:在安装驱动过程中配置 1、安装快要结束时会要求设置 secure boot密码

    2024年02月11日
    浏览(62)
  • ubuntu 22.04 AX211无法驱动

    安装完ubuntu 22.04发现自己的AX211无法驱动,找不到WiFi。查看dmesg日志发现: 然后就没有其它日志了,发现DEVICE是0x7A70,SUBSYSTEM_DEVICE为0x0244。看了Intel的WiFi驱动,说是AX210在5.10+的内核就支持了,AX211在5.14+的内核就支持。 https://wireless.wiki.kernel.org/en/users/Drivers/iwlwifi 而22.04的内核

    2024年02月11日
    浏览(118)
  • ubuntu22.04手动安装nvidia驱动

    借鉴大佬博客: https://blog.csdn.net/weixin_44123583/article/details/115613758 https://blog.csdn.net/zhangzeyuan56/article/details/122624768 (25条消息) Nvidia 显卡 Failed to initialize NVML Driver/library version mismatch 错误解决方案_苍蓝儿的博客-CSDN博客_failed to initialize nvml: driver/library version 查看合适显卡型号:在

    2024年02月04日
    浏览(68)
  • ubuntu22.04安装Nvidia显卡驱动

    Ubuntu 22.04安装NVIDIA显卡驱动的一般步骤: 注意:在执行这些步骤之前,请确保系统已连接到互联网,以便下载所需的软件包。 1. 检查NVIDIA显卡型号:打开终端,运行以下命令来确定NVIDIA显卡型号:    这将显示NVIDIA显卡型号,例如GeForce GTX 1050 Ti。 2. 更新系统: 在终端中,

    2024年01月16日
    浏览(68)
  • Ubuntu22.04 安装NVIDIA显卡驱动

    最近在想给自己电脑换成Linux系统的事情,但是过程没想到异常艰难,除了要安装一系列日常用软件和学习环境搭建外,还遇到了安装显卡驱动这个世纪难题[哭][哭],四处搜索度娘,最终还是让我暂时解决(安装成功)了这个难题,[再次感谢互联网各位大佬的扶持],所以,

    2024年02月08日
    浏览(73)
  • Ubuntu22.04安装及显卡驱动问题

    自己有window系统,想搞个ubuntu系统玩玩 首先去官网下载ubuntu系统,我下载的是22.04 https://cn.ubuntu.com/download/desktop 准备一个启动盘制作器Rufus,将下载好的镜像烤制到U盘 制作完u盘,进入bios更改启动顺序进入安装界面。我们进入安装界面,发现点了install ubuntu一直黑屏。这时需

    2024年02月09日
    浏览(50)
  • Ubuntu20.04、22.04安装nvidia显卡驱动

    资料1 https://huazhe1995.github.io/2020/01/01/ubuntu-an-zhuang-nvidia-qu-dong-run-fang-shi/ 资料2 https://blog.csdn.net/qq_51963216/article/details/124194096 资料3 https://blog.csdn.net/Perfect886/article/details/119109380 步骤: 1 1.安装驱动前一定要更新软件列表和安装必要软件、依赖(必须) 2.查看GPU型号 (你自己知道

    2024年02月06日
    浏览(87)
  • ubuntu22.04 出现附加驱动全部灰色,无法使用专有驱动

    原图忘记截屏了,现实问题是没有选择下面任何一个驱动,显示的是使用手动驱动,反正是一个都点不了,使用sudo 命令自动安装driver也出现了报错,根本不晓得如何解决 大概就是这上面所有的都灰色了,而且根本都点击不了。直接给整的绷不住了。。。。。 先在终端中输入

    2024年02月15日
    浏览(44)
  • Ubuntu 22.04 编译安装 Qt mysql驱动

    参考自 Ubuntu20.04.3 QT5.15.2 MySQL驱动编译 Ubuntu 18.04 编译安装 Qt mysql驱动 下边这篇博客不是主要参考的, 但是似乎解决了我的难题(找不到 libmysqlclient.so ) ubuntu18.04.2 LTS 系统关于Qt5.12.3 无法加载mysql驱动,需要重新编译MYSQL数据库驱动的问题以及解决方案 系统版本 MySQL 肯定要先安

    2024年01月16日
    浏览(66)
  • Ubuntu22.04 系统 安装驱动 && CUDA11.8

    参考: https://blog.csdn.net/weixin_43387635/article/details/126749463 Ubuntu22.04安装显卡驱动(高速、避错版)-CSDN博客 -------------------------------------------------安装驱动-------------------------------------------------------------------- 原作者说 需要注意的两条 ①   安装之前进入主板BIOS,关闭安全启动!!

    2024年03月27日
    浏览(68)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包